summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2025-04-12 20:04:50 -0700
committeriximeow <me@iximeow.net>2025-04-12 20:04:50 -0700
commit4005a6fe024cda0049e828aa688e1e9a885036f6 (patch)
tree61d43cf72a29bfe16b60fa570c7f754f88528cae
parentdc94ca8e9fb134f19e12977503a2b776d0864cb6 (diff)
more instruction extenders
-rw-r--r--src/lib.rs33
-rw-r--r--tests/from_brain.rs113
2 files changed, 128 insertions, 18 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 9010218..f681fb8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1158,7 +1158,7 @@ pub enum Operand {
RegCirc { base: u8, mu: u8 },
- RegStoreAssign { base: u8, addr: u16 },
+ RegStoreAssign { base: u8, addr: u32 },
RegMemIndexed { base: u8, mu: u8 },
@@ -4171,8 +4171,13 @@ fn decode_instruction<
} else {
let u2 = (inst >> 5) & 0b11;
let u4 = (inst >> 8) & 0b1111;
- let uuuuuu = (u2 | (u4 << 2)) as u16;
- handler.on_source_decoded(Operand::RegStoreAssign { base: xxxxx, addr: uuuuuu })?;
+ let uuuuuu = u2 | (u4 << 2);
+ handler.on_source_decoded(
+ Operand::with_extension(uuuuuu, extender,
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ )?
+ )?;
}
if !wide {
handler.on_dest_decoded(Operand::gpr(ddddd))?;
@@ -4193,8 +4198,13 @@ fn decode_instruction<
} else {
let u2 = (inst >> 5) & 0b11;
let u4 = (inst >> 8) & 0b1111;
- let uuuuuu = (u2 | (u4 << 2)) as u16;
- handler.on_source_decoded(Operand::RegStoreAssign { base: xxxxx, addr: uuuuuu })?;
+ let uuuuuu = (u2 | (u4 << 2)) as u32;
+ handler.on_source_decoded(
+ Operand::with_extension(uuuuuu, extender,
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ )?
+ )?;
}
if !wide {
handler.on_dest_decoded(Operand::gpr(ddddd))?;
@@ -4544,7 +4554,11 @@ fn decode_instruction<
let i11 = i_low | (i_mid << 8) | (i_high << 9);
decode_store_ops(handler, opc, ttttt, |shamt| {
- Ok(Operand::RegOffset { base: sssss, offset: i11 << shamt })
+ Operand::with_extension(
+ i11 << shamt, extender,
+ |offset| Ok(Operand::RegOffset { base: sssss, offset }),
+ |offset| Ok(Operand::RegOffset { base: sssss, offset }),
+ )
})?;
}
@@ -4600,9 +4614,12 @@ fn decode_instruction<
Ok(Operand::RegOffset { base: xxxxx, offset: iiii << shamt })
})?;
} else {
- let uuuuuu = (inst & 0b111111) as u16;
+ let uuuuuu = inst & 0b111111;
decode_store_ops(handler, minbits, ttttt, |_shamt| {
- Ok(Operand::RegStoreAssign { base: xxxxx, addr: uuuuuu })
+ Operand::with_extension(uuuuuu, extender,
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ |addr| Ok(Operand::RegStoreAssign { base: xxxxx, addr }),
+ )
})?;
}
} else {
diff --git a/tests/from_brain.rs b/tests/from_brain.rs
index 03751c5..8104b13 100644
--- a/tests/from_brain.rs
+++ b/tests/from_brain.rs
@@ -24,25 +24,25 @@ fn extenders() {
/*
* extendable instructions covered in this test:
* // it turns out these are encoded by applying an extender to the `mem{b,ub,...}(gp+#u16)` forms
- * [ ]: Rd = mem{b,ub,h,uh,w,d}(##U32)
+ * [x]: Rd = mem{b,ub,h,uh,w,d}(##U32)
* // predicated loads
* [ ]: if ([!]Pt[.new]) Rd = mem{b,ub,h,uh,w,d} (Rs + ##U32)
- * [ ]: Rd = mem{b,ub,h,uh,w,d} (Rs + ##U32)
- * [ ]: Rd = mem{b,ub,h,uh,w,d} (Re=##U32)
+ * [x]: Rd = mem{b,ub,h,uh,w,d} (Rs + ##U32)
+ * [x]: Rd = mem{b,ub,h,uh,w,d} (Re=##U32)
* [ ]: Rd = mem{b,ub,h,uh,w,d} (Rt<<#u2 + ##U32)
* [ ]: if ([!]Pt[.new]) Rd = mem{b,ub,h,uh,w,d} (##U32)
* // it turns out these are encoded by applying an extender to the `mem{b,ub,...}(gp+#u16)` forms
- * [ ]: mem{b,h,w,d}(##U32) = Rs[.new]
+ * [x]: mem{b,h,w,d}(##U32) = Rs[.new]
* // predicated stores
* [ ]: if ([!]Pt[.new]) mem{b,h,w,d}(Rs + ##U32) = Rt[.new]
- * [ ]: mem{b,h,w,d}(Rs + ##U32) = Rt[.new]
- * [ ]: mem{b,h,w,d}(Rd=##U32) = Rt[.new]
+ * [x]: mem{b,h,w,d}(Rs + ##U32) = Rt[.new]
+ * [x]: mem{b,h,w,d}(Rd=##U32) = Rt[.new]
* [ ]: mem{b,h,w,d}(Ru<<#u2 + ##U32) = Rt[.new]
* [ ]: if ([!]Pt[.new]) mem{b,h,w,d}(##U32) = Rt[.new]
* [ ]: [if [!]Ps] memw(Rs + #u6) = ##U32 // constant store
* [ ]: memw(Rs + Rt<<#u2) = ##U32 // constant store
* [ ]: if (cmp.xx(Rs.new,##U32)) jump:hint target
- * [ ]: Rd = ##u32
+ * [x]: Rd = ##u32
* [ ]: Rdd = combine(Rs,##u32)
* [ ]: Rdd = combine(##u32,Rs)
* [ ]: Rdd = combine(##u32,#s8)
@@ -56,9 +56,9 @@ fn extenders() {
* [ ]: Pd = [!]cmp.gt (Rs,##u32)
* [ ]: Pd = [!]cmp.gtu (Rs,##u32)
* [ ]: Rd = [!]cmp.eq(Rs,##u32)
- * [ ]: Rd = and(Rs,##u32)
- * [ ]: Rd = or(Rs,##u32)
- * [ ]: Rd = sub(##u32,Rs)
+ * [x]: Rd = and(Rs,##u32)
+ * [x]: Rd = or(Rs,##u32)
+ * [x]: Rd = sub(##u32,Rs)
* [ ]: Rd = add(Rs,##s32)
* [ ]: Rd = mpyi(Rs,##u32)
* [ ]: Rd += mpyi(Rs,##u32)
@@ -127,6 +127,7 @@ fn extenders() {
0x07, 0xc6, 0xc0, 0x48,
], "{ memd(##0x238) = r7:6 }");
+
test_display(&[
0x08, 0x40, 0x00, 0x00,
0xe6, 0xc1, 0x00, 0x49,
@@ -157,6 +158,7 @@ fn extenders() {
0xe6, 0xc0, 0xc0, 0x49,
], "{ r7:6 = memd(##0x238) }");
+
// HELP! it is somewhat unfortunate that extended offsets don't get the ## treatment like
// immediates. having different operands for all immediate-extended forms seems like a kind of
// bad idea though.
@@ -193,6 +195,97 @@ fn extenders() {
test_display(&[
0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0x05, 0x9b,
+ ], "{ r6 = memb(r5=#0x20f) }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0x25, 0x9b,
+ ], "{ r6 = memub(r5=#0x20f) }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0x45, 0x9b,
+ ], "{ r6 = memh(r5=#0x20f) }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0x65, 0x9b,
+ ], "{ r6 = memuh(r5=#0x20f) }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0x85, 0x9b,
+ ], "{ r6 = memw(r5=#0x20f) }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0xe6, 0xd3, 0xc5, 0x9b,
+ ], "{ r7:6 = memd(r5=#0x20f) }");
+
+
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xc6, 0x04, 0xa1,
+ ], "{ memb(r4+#527) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xc6, 0x44, 0xa1,
+ ], "{ memh(r4+#542) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xc6, 0x84, 0xa1,
+ ], "{ memw(r4+#572) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xc6, 0xa4, 0xa1,
+ ], "{ memb(r4+#527) = r6.new }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xce, 0xa4, 0xa1,
+ ], "{ memh(r4+#542) = r6.new }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xd6, 0xa4, 0xa1,
+ ], "{ memw(r4+#572) = r6.new }");
+ // the immediate of 1111 << 3 shifts a 1 out of the low 6 bits and invalidates the operand.
+ test_invalid(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x0f, 0xc6, 0xc4, 0xa1,
+ ], DecodeError::InvalidOperand);
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x07, 0xc6, 0xc4, 0xa1,
+ ], "{ memd(r4+#568) = r7:6 }");
+
+
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xc6, 0x04, 0xab,
+ ], "{ memb(r4=#0x20f) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xc6, 0x44, 0xab,
+ ], "{ memh(r4=#0x20f) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xc6, 0x84, 0xab,
+ ], "{ memw(r4=#0x20f) = r6 }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xc6, 0xa4, 0xab,
+ ], "{ memb(r4=#0x20f) = r6.new }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xce, 0xa4, 0xab,
+ ], "{ memh(r4=#0x20f) = r6.new }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x8f, 0xd6, 0xa4, 0xab,
+ ], "{ memw(r4=#0x20f) = r6.new }");
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
+ 0x87, 0xc6, 0xc4, 0xab,
+ ], "{ memd(r4=#0x207) = r7:6 }");
+
+
+ test_display(&[
+ 0x08, 0x40, 0x00, 0x00,
0x0f, 0xc6, 0x00, 0x48,
], "{ memb(##0x20f) = r6 }");
test_display(&[