diff --git a/core/rexcode/isa/arm32/decoder.odin b/core/rexcode/isa/arm32/decoder.odin index 633ad28e6..7e7c740f1 100644 --- a/core/rexcode/isa/arm32/decoder.odin +++ b/core/rexcode/isa/arm32/decoder.odin @@ -529,8 +529,15 @@ unpack_operand :: proc(word: u32, enc: Operand_Encoding, ot: Operand_Type) -> Op return op_imm(i64((word >> 18) & 0xF)) // ---- Saturate / bit field ---- - case .SAT_IMM5, .SAT_IMM5_T32, .BFI_MSB: - return op_imm(i64((word >> 16) & 0x1F)) + case .SAT_IMM5, .SAT_IMM5_T32: + // The field holds one less than the saturate position it names. + return op_imm(i64(((word >> 16) & 0x1F) + 1)) + case .BFX_WIDTH: + // One less than the width. + return op_imm(i64(((word >> 16) & 0x1F) + 1)) + case .BFI_MSB: + // The top bit's position; the syntax wants the width. + return op_imm(i64(((word >> 16) & 0x1F) - ((word >> 7) & 0x1F) + 1)) case .BFI_LSB, .BFI_LSB_T32: return op_imm(i64((word >> 7) & 0x1F)) case .NEON_SHIFT_IMM6: diff --git a/core/rexcode/isa/arm32/encoder.odin b/core/rexcode/isa/arm32/encoder.odin index d5b8a68b1..666266a27 100644 --- a/core/rexcode/isa/arm32/encoder.odin +++ b/core/rexcode/isa/arm32/encoder.odin @@ -202,10 +202,10 @@ encode_one_inline :: #force_inline proc( word = (word & 0x0FFFFFFF) | (u32(inst.cond) << 28) } - if form.enc[0] != .NONE { word |= pack_operand_inline(&inst.ops[0], form.enc[0], pc, inst_idx, relocs, form) } - if form.enc[1] != .NONE { word |= pack_operand_inline(&inst.ops[1], form.enc[1], pc, inst_idx, relocs, form) } - if form.enc[2] != .NONE { word |= pack_operand_inline(&inst.ops[2], form.enc[2], pc, inst_idx, relocs, form) } - if form.enc[3] != .NONE { word |= pack_operand_inline(&inst.ops[3], form.enc[3], pc, inst_idx, relocs, form) } + if form.enc[0] != .NONE { word |= pack_operand_inline(&inst.ops[0], form.enc[0], pc, inst_idx, relocs, form, inst) } + if form.enc[1] != .NONE { word |= pack_operand_inline(&inst.ops[1], form.enc[1], pc, inst_idx, relocs, form, inst) } + if form.enc[2] != .NONE { word |= pack_operand_inline(&inst.ops[2], form.enc[2], pc, inst_idx, relocs, form, inst) } + if form.enc[3] != .NONE { word |= pack_operand_inline(&inst.ops[3], form.enc[3], pc, inst_idx, relocs, form, inst) } return word, inst_size_from_bits(form.bits, form.mode), true } @@ -334,6 +334,8 @@ pack_operand_inline :: #force_inline proc( inst_idx: u16, relocs: ^[dynamic]Relocation, form: ^Encoding, + // BFI's msb is lsb + width - 1, so packing it needs a sibling operand. + inst: ^Instruction, ) -> u32 { switch enc { case .NONE, .IMPL: @@ -631,9 +633,15 @@ pack_operand_inline :: #force_inline proc( case .IT_MASK: return u32(op.immediate) & 0xFF case .CPS_IFLAGS: return u32(op.immediate) & 0x1FF case .HINT_FIELD: return u32(op.immediate) & 0xFF - case .SAT_IMM5, .SAT_IMM5_T32: - return (u32(op.immediate) & 0x1F) << 16 - case .BFI_MSB: return (u32(op.immediate) & 0x1F) << 16 + case .SAT_IMM5, .SAT_IMM5_T32, .BFX_WIDTH: + return ((u32(op.immediate) - 1) & 0x1F) << 16 + case .BFI_MSB: + // msb = lsb + width - 1; the lsb rides in whichever slot carries it. + lsb: u32 = 0 + for e, k in form.enc { + if e == .BFI_LSB || e == .BFI_LSB_T32 { lsb = u32(inst.ops[k].immediate); break } + } + return ((lsb + u32(op.immediate) - 1) & 0x1F) << 16 case .BFI_LSB, .BFI_LSB_T32: return (u32(op.immediate) & 0x1F) << 7 case .NEON_SHIFT_IMM6: return (u32(op.immediate) & 0x3F) << 16 diff --git a/core/rexcode/isa/arm32/encoding_types.odin b/core/rexcode/isa/arm32/encoding_types.odin index d600b6a88..82643db9d 100644 --- a/core/rexcode/isa/arm32/encoding_types.odin +++ b/core/rexcode/isa/arm32/encoding_types.odin @@ -400,6 +400,9 @@ Operand_Encoding :: enum u8 { SAT_IMM5_T32, // Thumb-2 saturate amount // ---- BFC/BFI/SBFX/UBFX ---- + // SBFX/UBFX hold the width less one, where BFI/BFC hold the top bit's + // position and the width is msb - lsb + 1. + BFX_WIDTH, BFI_MSB, // bits 20-16 (msb position) BFI_LSB, // bits 11-7 (lsb position; also shift_imm slot) BFI_LSB_T32, // Thumb-2 BFI lsb (different layout) diff --git a/core/rexcode/isa/arm32/tablegen/encoding_table.odin b/core/rexcode/isa/arm32/tablegen/encoding_table.odin index 1f67e57ea..ec127ce1a 100644 --- a/core/rexcode/isa/arm32/tablegen/encoding_table.odin +++ b/core/rexcode/isa/arm32/tablegen/encoding_table.odin @@ -754,14 +754,14 @@ ENCODING_TABLE := #partial [Mnemonic][]Encoding{ {.BFI, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD_T32, .RN_T32, .BFI_LSB_T32, .BFI_MSB}, 0xF3600000, 0xFFF08000, .V6T2, .T32, {thumb32=true, cond_in_28=false}, {}}, }, .SBFX = { - {.SBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD, .RM_A32, .BFI_LSB, .BFI_MSB}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {}}, + {.SBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD, .RM_A32, .BFI_LSB, .BFX_WIDTH}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {}}, // T32 SBFX - {.SBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD_T32, .RN_T32, .BFI_LSB_T32, .BFI_MSB}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true, cond_in_28=false}, {}}, + {.SBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD_T32, .RN_T32, .BFI_LSB_T32, .BFX_WIDTH}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true, cond_in_28=false}, {}}, }, .UBFX = { - {.UBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD, .RM_A32, .BFI_LSB, .BFI_MSB}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {}}, + {.UBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD, .RM_A32, .BFI_LSB, .BFX_WIDTH}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {}}, // T32 UBFX - {.UBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD_T32, .RN_T32, .BFI_LSB_T32, .BFI_MSB}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true, cond_in_28=false}, {}}, + {.UBFX, {.GPR, .GPR, .IMM5, .IMM5_W}, {.RD_T32, .RN_T32, .BFI_LSB_T32, .BFX_WIDTH}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true, cond_in_28=false}, {}}, }, // ========================================================================= diff --git a/core/rexcode/isa/arm32/tablegen/generated/decode_tables.odin b/core/rexcode/isa/arm32/tablegen/generated/decode_tables.odin index f7f3870a1..fbf32d8d7 100644 --- a/core/rexcode/isa/arm32/tablegen/generated/decode_tables.odin +++ b/core/rexcode/isa/arm32/tablegen/generated/decode_tables.odin @@ -979,10 +979,10 @@ DECODE_ENTRIES := [1649]lib.Decode_Entry{ { .LDRB, {.GPR,.MEM,.NONE,.NONE}, {.RT_A32,.MEM_REG_OFFSET,.NONE,.NONE}, 0x07500000, 0x0F700010, .BASE, .A32, {}, {.NONE,.NONE} }, { .USAD8, {.GPR,.GPR,.GPR,.NONE}, {.RN_A32,.RM_A32,.RS_A32,.NONE}, 0x0780F010, 0x0FF0F0F0, .V6, .A32, {}, {.NONE,.NONE} }, { .USADA8, {.GPR,.GPR,.GPR,.GPR}, {.RN_A32,.RM_A32,.RS_A32,.RD}, 0x07800010, 0x0FF000F0, .V6, .A32, {}, {.NONE,.NONE} }, - { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, + { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFX_WIDTH}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, { .BFC, {.GPR,.IMM5,.IMM5_W,.NONE}, {.RD,.BFI_LSB,.BFI_MSB,.NONE}, 0x07C0001F, 0x0FE0007F, .V6T2, .A32, {}, {.NONE,.NONE} }, { .BFI, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07C00010, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, - { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, + { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFX_WIDTH}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, { .UDF, {.IMM,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0xE7F000F0, 0xFFF000F0, .BASE, .A32, {}, {.NONE,.NONE} }, { .STMDA, {.GPR,.GPR_LIST,.NONE,.NONE}, {.RN_A32,.A32_REG_LIST,.NONE,.NONE}, 0x08000000, 0x0FD00000, .BASE, .A32, {}, {.NONE,.NONE} }, { .RFE, {.GPR,.NONE,.NONE,.NONE}, {.RN_A32,.NONE,.NONE,.NONE}, 0xF8100A00, 0xFE10FFFF, .V6, .A32, {}, {.NONE,.NONE} }, @@ -1407,8 +1407,8 @@ DECODE_ENTRIES := [1649]lib.Decode_Entry{ { .USAT16, {.GPR,.IMM4_SAT,.GPR,.NONE}, {.RD_T32,.SAT_IMM5_T32,.RN_T32,.NONE}, 0xF3A00000, 0xFFF0F0F0, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, { .BFC, {.GPR,.IMM5,.IMM5_W,.NONE}, {.RD_T32,.BFI_LSB_T32,.BFI_MSB,.NONE}, 0xF36F0000, 0xFFFF8000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, { .BFI, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3600000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, - { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, - { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, + { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFX_WIDTH}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, + { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFX_WIDTH}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, { .SSAT, {.GPR,.IMM4_SAT,.GPR_SHIFTED,.NONE}, {.RD_T32,.SAT_IMM5_T32,.RN_T32,.NONE}, 0xF3000000, 0xFFD08020, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, { .USAT, {.GPR,.IMM4_SAT,.GPR_SHIFTED,.NONE}, {.RD_T32,.SAT_IMM5_T32,.RN_T32,.NONE}, 0xF3800000, 0xFFD08020, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, { .MOVW, {.GPR,.IMM16_LO_HI,.NONE,.NONE}, {.RD_T32,.NONE,.NONE,.NONE}, 0xF2400000, 0xFBF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, diff --git a/core/rexcode/isa/arm32/tablegen/generated/encode_tables.odin b/core/rexcode/isa/arm32/tablegen/generated/encode_tables.odin index 9bcca5dae..7b0e2b271 100644 --- a/core/rexcode/isa/arm32/tablegen/generated/encode_tables.odin +++ b/core/rexcode/isa/arm32/tablegen/generated/encode_tables.odin @@ -209,11 +209,11 @@ ENCODE_FORMS := [1649]lib.Encoding{ { .BFI, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07C00010, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, { .BFI, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3600000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, // .SBFX - { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, - { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, + { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFX_WIDTH}, 0x07A00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, + { .SBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFX_WIDTH}, 0xF3400000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, // .UBFX - { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFI_MSB}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, - { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFI_MSB}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, + { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD,.RM_A32,.BFI_LSB,.BFX_WIDTH}, 0x07E00050, 0x0FE00070, .V6T2, .A32, {}, {.NONE,.NONE} }, + { .UBFX, {.GPR,.GPR,.IMM5,.IMM5_W}, {.RD_T32,.RN_T32,.BFI_LSB_T32,.BFX_WIDTH}, 0xF3C00000, 0xFFF08000, .V6T2, .T32, {thumb32=true}, {.NONE,.NONE} }, // .SXTB { .SXTB, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RM_A32,.NONE,.NONE}, 0x06AF0070, 0x0FFF0070, .V6, .A32, {}, {.NONE,.NONE} }, { .SXTB, {.GPR_LOW,.GPR_LOW,.NONE,.NONE}, {.RD_T16_LO,.RM_T16_LO,.NONE,.NONE}, 0x0000B240, 0x0000FFC0, .V6, .T32, {}, {.NONE,.NONE} }, diff --git a/core/rexcode/isa/arm32/tables/arm32.encode_forms.bin b/core/rexcode/isa/arm32/tables/arm32.encode_forms.bin index c3ad6e7d8..510521e93 100644 Binary files a/core/rexcode/isa/arm32/tables/arm32.encode_forms.bin and b/core/rexcode/isa/arm32/tables/arm32.encode_forms.bin differ diff --git a/core/rexcode/isa/arm32/tables/arm32.entries.bin b/core/rexcode/isa/arm32/tables/arm32.entries.bin index b6b1772d5..c02fc29c0 100644 Binary files a/core/rexcode/isa/arm32/tables/arm32.entries.bin and b/core/rexcode/isa/arm32/tables/arm32.entries.bin differ