diff options
Diffstat (limited to 'v5/apf_interpreter.c')
-rw-r--r-- | v5/apf_interpreter.c | 59 |
1 files changed, 32 insertions, 27 deletions
diff --git a/v5/apf_interpreter.c b/v5/apf_interpreter.c index 84afca8..f71db4d 100644 --- a/v5/apf_interpreter.c +++ b/v5/apf_interpreter.c @@ -260,6 +260,7 @@ typedef union { /* NOTE: Only APFv6+ implements R=1 'jbseq' version */ #define EXT_OPCODE 21 /* Immediate value is one of *_EXT_OPCODE */ #define LDDW_OPCODE 22 /* Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]" */ + /* LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm. */ #define STDW_OPCODE 23 /* Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]" */ /* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer. @@ -595,7 +596,7 @@ extern void APF_TRACE_HOOK(u32 pc, const u32* regs, const u8* program, #define ENFORCE_UNSIGNED(c) ((c)==(u32)(c)) u32 apf_version(void) { - return 20240313; + return 20240314; } typedef struct { @@ -975,34 +976,38 @@ static int do_apf_run(apf_context* ctx) { return PASS_PACKET; /* Bail out */ } break; - case LDDW_OPCODE: { - u32 offs = OTHER_REG + (u32)signed_imm; - u32 size = 4; - u32 val = 0; - /* Negative offsets wrap around the end of the address space. */ - /* This allows us to efficiently access the end of the */ - /* address space with one-byte immediates without using %=. */ - if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */ - ASSERT_IN_DATA_BOUNDS(offs, size); - while (size--) val = (val << 8) | ctx->program[offs++]; - REG = val; - break; - } - case STDW_OPCODE: { - u32 offs = OTHER_REG + (u32)signed_imm; - u32 size = 4; - u32 val = REG; - /* Negative offsets wrap around the end of the address space. */ - /* This allows us to efficiently access the end of the */ - /* address space with one-byte immediates without using %=. */ - if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */ - ASSERT_IN_DATA_BOUNDS(offs, size); - while (size--) { - ctx->program[offs++] = (val >> 24); - val <<= 8; + case LDDW_OPCODE: + case STDW_OPCODE: + if (ctx->v6) { + if (!imm) return PASS_PACKET; + if (imm > 0xFFFF) return PASS_PACKET; + if (imm * 4 > ctx->ram_len) return PASS_PACKET; + if (opcode == LDDW_OPCODE) { + REG = counter[-(s32)imm]; + } else { + counter[-(s32)imm] = REG; + } + } else { + u32 offs = OTHER_REG + (u32)signed_imm; + /* Negative offsets wrap around the end of the address space. */ + /* This allows us to efficiently access the end of the */ + /* address space with one-byte immediates without using %=. */ + if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */ + u32 size = 4; + ASSERT_IN_DATA_BOUNDS(offs, size); + if (opcode == LDDW_OPCODE) { + u32 val = 0; + while (size--) val = (val << 8) | ctx->program[offs++]; + REG = val; + } else { + u32 val = REG; + while (size--) { + ctx->program[offs++] = (val >> 24); + val <<= 8; + } + } } break; - } case WRITE_OPCODE: { ASSERT_RETURN(ctx->tx_buf); ASSERT_RETURN(len_field); |