From 96847c9d1f17d745fd1538ee18c9411df0e2b138 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 13 Apr 2025 18:54:11 -0700 Subject: l2 cache management instructions are system and undocumented --- src/display.rs | 4 ++++ src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++++--------- tests/from_brain.rs | 7 ++++++- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/display.rs b/src/display.rs index a9e5e49..6827108 100644 --- a/src/display.rs +++ b/src/display.rs @@ -717,6 +717,10 @@ impl fmt::Display for Opcode { Opcode::DcKill => { f.write_str("dckill") }, Opcode::IcKill => { f.write_str("ickill") }, Opcode::L2Fetch => { f.write_str("l2fetch") }, + Opcode::L2Kill => { f.write_str("l2kill") }, + Opcode::L2Gunlock => { f.write_str("l2gunlock") }, + Opcode::L2Gclean => { f.write_str("l2gclean") }, + Opcode::L2Gcleaninv => { f.write_str("l2gcleaninv") }, Opcode::DmSyncHt => { f.write_str("dmsyncht") }, Opcode::SyncHt => { f.write_str("syncht") }, diff --git a/src/lib.rs b/src/lib.rs index 12e6fd1..b5ffe05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -649,6 +649,10 @@ pub enum Opcode { DcKill, IcKill, L2Fetch, + L2Kill, + L2Gunlock, + L2Gclean, + L2Gcleaninv, DmSyncHt, SyncHt, @@ -5088,19 +5092,36 @@ fn decode_instruction< } else { // if there are any encodings like 1010|010, they are not in the V73 // manual... + // + // ... surprise! L2 cache management instructions are system instructions + // and last described in the V65 manual. opcode_check!(opc_upper == 0b11); let opc_lower = (inst >> 21) & 0b111; - // similar.. - opcode_check!(opc_lower & 0b11 == 0b00); - handler.on_opcode_decoded(Opcode::L2Fetch)?; - handler.on_source_decoded(Rs)?; let ttttt = reg_b8(inst); - if opc_lower == 0b100 { - handler.on_source_decoded(Operand::gprpair(ttttt)?)?; - } else { - opcode_check!((inst >> 5) & 0b111 == 0b000); - handler.on_source_decoded(Operand::gpr(ttttt))?; + match opc_lower { + 0b000 => { + handler.on_opcode_decoded(Opcode::L2Fetch)?; + handler.on_source_decoded(Rs)?; + opcode_check!((inst >> 5) & 0b111 == 0b000); + handler.on_source_decoded(Operand::gpr(ttttt))?; + } + 0b100 => { + handler.on_opcode_decoded(Opcode::L2Fetch)?; + handler.on_source_decoded(Rs)?; + handler.on_source_decoded(Operand::gprpair(ttttt)?)?; + } + 0b101 => { + handler.on_opcode_decoded(Opcode::L2Gclean)?; + handler.on_source_decoded(Operand::gprpair(ttttt)?)?; + } + 0b110 => { + handler.on_opcode_decoded(Opcode::L2Gcleaninv)?; + handler.on_source_decoded(Operand::gprpair(ttttt)?)?; + } + _ => { + opcode_check!(false); + } } } } else { @@ -5133,8 +5154,17 @@ fn decode_instruction< 0b000 => { // barrier, dmsyncht, syncht. not much here (maybe these are supervisor // instructions?) + // + // ... yes! l2 cache operations are packed in here. if inst & 0x00_e0_00_e0 == 0 { handler.on_opcode_decoded(Opcode::Barrier)?; + } else if inst & 0x00_e0_00_00 == 0x00_20_00_00 { + let op = (inst >> 10) & 0b111; + static OPCODES: [Option; 8] = [ + Some(L2Kill), None, Some(L2Gunlock), None, + Some(L2Gclean), None, Some(L2Gcleaninv), None, + ]; + handler.on_opcode_decoded(decode_opcode!(OPCODES[op as usize]))?; } else if inst & 0x00_e0_01_e0 == 0x00_00_00_e0 { handler.on_opcode_decoded(Opcode::DmSyncHt)?; handler.on_dest_decoded(Operand::gpr(inst as u8 & 0b11111))?; diff --git a/tests/from_brain.rs b/tests/from_brain.rs index 987bef7..7812247 100644 --- a/tests/from_brain.rs +++ b/tests/from_brain.rs @@ -1435,6 +1435,12 @@ fn inst_1010() { test_display(&0b1010_0110000_00010_11_0_00100_000_01011u32.to_le_bytes(), "{ l2fetch(r2, r4) }"); test_invalid(&0b1010_0110000_00010_11_0_00100_001_01011u32.to_le_bytes(), DecodeError::InvalidOpcode); test_display(&0b1010_0110100_00010_11_0_00100_000_01011u32.to_le_bytes(), "{ l2fetch(r2, r5:4) }"); + test_display(&0b1010_0110101_00010_11_0_00100_000_01011u32.to_le_bytes(), "{ l2gclean(r5:4) }"); + test_display(&0b1010_0110110_00010_11_0_00100_000_01011u32.to_le_bytes(), "{ l2gcleaninv(r5:4) }"); + test_display(&0b1010_1000001_00010_11_0_00000_000_01011u32.to_le_bytes(), "{ l2kill }"); + test_display(&0b1010_1000001_00010_11_0_01000_000_01011u32.to_le_bytes(), "{ l2gunlock }"); + test_display(&0b1010_1000001_00010_11_0_10000_000_01011u32.to_le_bytes(), "{ l2gclean }"); + test_display(&0b1010_1000001_00010_11_0_11000_000_01011u32.to_le_bytes(), "{ l2gcleaninv }"); test_display(&0b1010_0101000_00010_11_1_00100_000_01011u32.to_le_bytes(), "{ memb(r2+#1291) = r4 }"); test_display(&0b1010_0101010_00010_11_1_00100_000_01011u32.to_le_bytes(), "{ memh(r2+#2582) = r4 }"); @@ -1452,7 +1458,6 @@ fn inst_1010() { test_invalid(&0b1010_1000000_00010_11_1_00000_001_01011u32.to_le_bytes(), DecodeError::InvalidOpcode); test_invalid(&0b1010_1000000_00010_11_1_00000_010_01011u32.to_le_bytes(), DecodeError::InvalidOpcode); test_invalid(&0b1010_1000000_00010_11_1_00000_100_01011u32.to_le_bytes(), DecodeError::InvalidOpcode); - test_invalid(&0b1010_1000001_00010_11_1_00000_100_01011u32.to_le_bytes(), DecodeError::InvalidOpcode); test_display(&0b1010_1000010_00010_11_1_00000_111_01011u32.to_le_bytes(), "{ syncht }"); test_display(&0b1010_1001000_00010_11_1_00011_000_00010u32.to_le_bytes(), "{ memb(r2++I:circ(m1)) = r3 }"); -- cgit v1.1