diff options
| author | iximeow <me@iximeow.net> | 2025-04-08 23:44:42 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2025-04-08 23:44:42 -0700 | 
| commit | 2bf4b55491d2100734089652fce2048d711ac71a (patch) | |
| tree | 4a009d2229ef1decb4ab4001166e4b7a2de2de51 | |
| parent | f902e9a1df4f7b03c029491e72aca72977d23f5b (diff) | |
supervisor mode instructions, control register names
| -rw-r--r-- | src/display.rs | 64 | ||||
| -rw-r--r-- | src/lib.rs | 118 | ||||
| -rw-r--r-- | tests/from_brain.rs | 34 | 
3 files changed, 203 insertions, 13 deletions
| diff --git a/src/display.rs b/src/display.rs index 071633c..0c8e366 100644 --- a/src/display.rs +++ b/src/display.rs @@ -775,6 +775,26 @@ impl fmt::Display for Opcode {              // shouldn't ever really be printed as `addasl` (instruction display has more complex              // rules here.              Opcode::AddAslRegReg => { f.write_str("addasl") }, +            Opcode::Swi => { f.write_str("swi") }, +            Opcode::Cswi => { f.write_str("cswi") }, +            Opcode::Ciad => { f.write_str("ciad") }, +            Opcode::Wait => { f.write_str("wait") }, +            Opcode::Resume => { f.write_str("resume") }, +            Opcode::Stop => { f.write_str("stop") }, +            Opcode::Start => { f.write_str("start") }, +            Opcode::Nmi => { f.write_str("nmi") }, +            Opcode::Setimask => { f.write_str("setimask") }, +            Opcode::Siad => { f.write_str("siad") }, +            Opcode::Brkpt => { f.write_str("brkpt") }, +            Opcode::TlbLock => { f.write_str("tlblock") }, +            Opcode::K0Lock => { f.write_str("k0lock") }, +            Opcode::Crswap => { f.write_str("crswap") }, +            Opcode::Getimask => { f.write_str("getimask") }, +            Opcode::Iassignr => { f.write_str("iassignr") }, +            Opcode::Icdatar => { f.write_str("icdatar") }, +            Opcode::Ictagr => { f.write_str("ictagr") }, +            Opcode::Icinvidx => { f.write_str("icinvidx") }, +              Opcode::SubAsl => { f.write_str("subasl") },              Opcode::AndAsl => { f.write_str("andasl") },              Opcode::AddClb => { f.write_str("addclb") }, @@ -919,18 +939,34 @@ impl fmt::Display for Operand {                  write!(f, "R{}", reg)              }              Operand::Cr { reg } => { +                // V69 Table 2-2 Aliased control registers +                static CR_NAMES: [&'static str; 32] = [ +                    "sa0", "lc0", "sa1", "lc1", +                    "P3:0", "C5", "M0", "M1", +                    "usr", "pc", "ugp", "gp", +                    "cs0", "cs1", "upcyclelo", "upcyclehi", +                    "framelimit", "framekey", "pktcountlo", "pktcounthi", +                    "C20", "C21", "C22", "C23", +                    "C24", "C25", "C26", "C27", +                    "C28", "C29", "utimerlo", "utimerhi", +                ]; +                f.write_str(CR_NAMES[*reg as usize]) +            } +            Operand::Sr { reg } => { +                // TODO: System control register transfer +                // from v62                  match reg { -                    9 => { -                        f.write_str("pc") +                    0 => { +                        f.write_str("sgp0") +                    } +                    1 => { +                        f.write_str("sgp1")                      }                      reg => { -                        write!(f, "C{}", reg) +                        write!(f, "S{}", reg)                      }                  }              } -            Operand::Sr { reg } => { -                write!(f, "S{}", reg) -            }              Operand::GprNew { reg } => {                  write!(f, "R{}.new", reg)              } @@ -950,10 +986,22 @@ impl fmt::Display for Operand {                  write!(f, "R{}:{}*", reg_low + 1, reg_low)              }              Operand::Cr64b { reg_low } => { -                write!(f, "C{}:{}", reg_low + 1, reg_low) +                if *reg_low == 14 { +                    f.write_str("upcycle") +                } else if *reg_low == 18 { +                    f.write_str("pktcount") +                } else if *reg_low == 30 { +                    f.write_str("utimer") +                } else { +                    write!(f, "C{}:{}", reg_low + 1, reg_low) +                }              }              Operand::Sr64b { reg_low } => { -                write!(f, "S{}:{}", reg_low + 1, reg_low) +                if *reg_low == 0 { +                    f.write_str("sgp1:0") +                } else { +                    write!(f, "S{}:{}", reg_low + 1, reg_low) +                }              }              Operand::PredicateReg { reg } => {                  write!(f, "P{}", reg) @@ -825,6 +825,26 @@ pub enum Opcode {      // `add(x, asl(y, z))` that would be used below. terrible.      AddAslRegReg, +    Swi, +    Cswi, +    Ciad, +    Wait, +    Resume, +    Stop, +    Start, +    Nmi, +    Setimask, +    Siad, +    Brkpt, +    TlbLock, +    K0Lock, +    Crswap, +    Getimask, +    Iassignr, +    Icdatar, +    Ictagr, +    Icinvidx, +      AndAnd = 0x8000,      AndOr,      OrAnd, @@ -2366,6 +2386,14 @@ fn decode_instruction<                          let xxxxx = reg_b16(inst);                          handler.on_source_decoded(Operand::gpr(xxxxx))?;                          handler.on_source_decoded(Operand::imm_u8(u_8 as u8))?; +                    } else if minbits == 0b110 { +                        handler.on_opcode_decoded(Opcode::Icdatar)?; +                        handler.on_dest_decoded(Operand::gpr(reg_b0(inst)))?; +                        handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                    } else if minbits == 0b111 { +                        handler.on_opcode_decoded(Opcode::Ictagr)?; +                        handler.on_dest_decoded(Operand::gpr(reg_b0(inst)))?; +                        handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;                      } else {                          opcode_check!(false);                      } @@ -2378,6 +2406,9 @@ fn decode_instruction<                          handler.on_opcode_decoded(Opcode::Icinva)?;                          handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;                          opcode_check!(inst & 0x3800 == 0x0000); +                    } else if minbits == 0b0111 { +                        handler.on_opcode_decoded(Opcode::Icinvidx)?; +                        handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;                      } else if minbits == 0b1110 {                          handler.on_opcode_decoded(Opcode::Isync)?;                          opcode_check!(inst & 0x1f23ff == 0x000002); @@ -2597,6 +2628,71 @@ fn decode_instruction<                          _ => { return Err(DecodeError::InvalidOpcode); }                      };                  } +                0b0100000 => { +                    // 000 -> swi +                    // 001 -> cswi +                    // 011 -> ciad +                    // TODO: +                    static OPS: [Option<Opcode>; 8] = [ +                        Some(Opcode::Swi), Some(Opcode::Cswi), None, Some(Opcode::Ciad), +                        None, None, None, None, +                    ]; +                    handler.on_opcode_decoded(decode_opcode!(OPS[((inst >> 5) & 0b111) as usize]))?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                } +                0b0100010 => { +                    // 000 -> wait +                    // 010 -> resume +                    // TODO: +                    static OPS: [Option<Opcode>; 8] = [ +                        Some(Opcode::Wait), None, Some(Opcode::Resume), None, +                        None, None, None, None, +                    ]; +                    handler.on_opcode_decoded(decode_opcode!(OPS[((inst >> 5) & 0b111) as usize]))?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                } +                0b0100011 => { +                    // 000 -> stop +                    // 001 -> start +                    // 010 -> nmi +                    // TODO: +                    static OPS: [Option<Opcode>; 8] = [ +                        Some(Opcode::Stop), Some(Opcode::Start), Some(Opcode::Nmi), None, +                        None, None, None, None, +                    ]; +                    handler.on_opcode_decoded(decode_opcode!(OPS[((inst >> 5) & 0b111) as usize]))?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                } +                0b0100100 => { +                    // TODO: double check encoding and manual +                    // 000 -> setimask +                    // 011 -> siad +                    static OPS: [Option<Opcode>; 8] = [ +                        Some(Opcode::Setimask), None, None, Some(Opcode::Siad), +                        None, None, None, None, +                    ]; +                    let opc = (inst >> 5) & 0b111; +                    handler.on_opcode_decoded(decode_opcode!(OPS[opc as usize]))?; +                    if opc == 0b000 { +                        handler.on_source_decoded(Operand::pred(reg_b0(inst) & 0b11))?; +                    } +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                } +                0b0101000 => { +                    handler.on_opcode_decoded(Opcode::Crswap)?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                    handler.on_source_decoded(Operand::sr(0))?; +                } +                0b0101001 => { +                    handler.on_opcode_decoded(Opcode::Crswap)?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                    handler.on_source_decoded(Operand::sr(1))?; +                } +                0b0110000 => { +                    handler.on_opcode_decoded(Opcode::Getimask)?; +                    handler.on_dest_decoded(Operand::gpr(reg_b0(inst)))?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                }                  0b0111000 => {                      // not in V73! store to supervisor register?                      let sssss = reg_b16(inst); @@ -2607,8 +2703,14 @@ fn decode_instruction<                  }                  // TODO: 1001000 loop0 goes here                  0b1100001 => { -                    opcode_check!((inst >> 5) & 0b111 == 0); -                    handler.on_opcode_decoded(Opcode::Barrier)?; +                    // 000 -> brkpt +                    // 001 -> tlblock +                    // 011 -> k0lock +                    static OPS: [Option<Opcode>; 8] = [ +                        Some(Opcode::Brkpt), Some(Opcode::TlbLock), None, Some(Opcode::K0Lock), +                        None, None, None, None, +                    ]; +                    handler.on_opcode_decoded(decode_opcode!(OPS[((inst >> 5) & 0b111) as usize]))?;                  }                  0b1101000 => {                      // not in V73! store to supervisor register? @@ -2618,6 +2720,18 @@ fn decode_instruction<                      handler.on_dest_decoded(Operand::srpair(ddddddd as u8)?)?;                      handler.on_source_decoded(Operand::gprpair(sssss)?)?;                  } +                0b1101100 => { +                    operand_check!(reg_b0(inst) == 0); +                    // TODO: +                    handler.on_opcode_decoded(Opcode::Crswap)?; +                    handler.on_source_decoded(Operand::gprpair(reg_b16(inst))?)?; +                    handler.on_source_decoded(Operand::srpair(0)?)?; +                } +                0b1110011 => { +                    handler.on_opcode_decoded(Opcode::Iassignr)?; +                    handler.on_dest_decoded(Operand::gpr(reg_b0(inst)))?; +                    handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?; +                }                  0b1110100 | 0b1110101 |                  0b1110110 | 0b1110111 => {                      // not in V73! load supervisor register? diff --git a/tests/from_brain.rs b/tests/from_brain.rs index 14be5ff..df6880a 100644 --- a/tests/from_brain.rs +++ b/tests/from_brain.rs @@ -18,8 +18,36 @@ fn test_invalid(bytes: &[u8], expected: DecodeError) {      assert_eq!(err, expected);  } +// mentioned in the V62 manual, not later? +// not sure if these are still what they seem in later versions, but until demonstrated +// otherwise...  #[test]  fn supervisor() { +    test_display(&0b0101_010_1101_00010_11_0_01000_000_00110u32.to_le_bytes(), "{ R6 = icdatar(R2) }"); +    test_display(&0b0101_010_1111_00010_11_0_01000_000_00110u32.to_le_bytes(), "{ R6 = ictagr(R2) }"); +    test_display(&0b0101_011_0111_00010_11_0_01000_000_00110u32.to_le_bytes(), "{ icinvidx(R2) }"); + +    test_display(&0b0110_01_00000_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ swi(R6) }"); +    test_display(&0b0110_01_00000_00110_11_0_00010_001_10110u32.to_le_bytes(), "{ cswi(R6) }"); +    test_display(&0b0110_01_00000_00110_11_0_00010_011_10110u32.to_le_bytes(), "{ ciad(R6) }"); +    test_display(&0b0110_01_00010_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ wait(R6) }"); +    test_display(&0b0110_01_00010_00110_11_0_00010_010_10110u32.to_le_bytes(), "{ resume(R6) }"); +    test_display(&0b0110_01_00011_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ stop(R6) }"); +    test_display(&0b0110_01_00011_00110_11_0_00010_001_10110u32.to_le_bytes(), "{ start(R6) }"); +    test_display(&0b0110_01_00011_00110_11_0_00010_010_10110u32.to_le_bytes(), "{ nmi(R6) }"); +    test_display(&0b0110_01_00100_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ setimask(P2, R6) }"); +    test_display(&0b0110_01_00100_00110_11_0_00010_011_10110u32.to_le_bytes(), "{ siad(R6) }"); +    test_display(&0b0110_01_01000_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ crswap(R6, sgp0) }"); +    test_display(&0b0110_01_01001_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ crswap(R6, sgp1) }"); +    test_display(&0b0110_01_10000_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ R22 = getimask(R6) }"); +    test_display(&0b0110_11_00001_00110_11_0_00010_000_10110u32.to_le_bytes(), "{ brkpt }"); +    test_display(&0b0110_11_00001_00110_11_0_00010_001_00000u32.to_le_bytes(), "{ tlblock }"); +    test_display(&0b0110_11_00001_00110_11_0_00010_011_00000u32.to_le_bytes(), "{ k0lock }"); +    test_display(&0b0110_11_01100_00110_11_0_00010_000_00000u32.to_le_bytes(), "{ crswap(R7:6, sgp1:0) }"); +    test_invalid(&0b0110_11_01100_00110_11_0_00010_000_00001u32.to_le_bytes(), DecodeError::InvalidOperand); +    test_display(&0b0110_11_10011_00110_11_0_00010_011_10110u32.to_le_bytes(), "{ R22 = iassignr(R6) }"); + +    // ok      test_display(&0b0110_0111000_00010_11_0011010_0000110u32.to_le_bytes(), "{ S6 = R2 }");      test_display(&0b0110_1101000_00010_11_0011010_0000110u32.to_le_bytes(), "{ S7:6 = R3:2 }"); @@ -264,6 +292,7 @@ fn inst_0101() {      test_display(&0b0101_010_0010_00010_11_0_01000_000_00010u32.to_le_bytes(), "{ pause(#0x240) }");      test_display(&0b0101_010_0100_00010_11_0_01000_000_00010u32.to_le_bytes(), "{ trap1(R2, #0x40) }");      test_invalid(&0b0101_010_0110_00010_11_0_01000_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode); +      test_invalid(&0b0101_011_0101_00010_11_0_01000_000_00010u32.to_le_bytes(), DecodeError::InvalidOpcode);      test_display(&0b0101_011_0110_00010_11_0_00000_000_00000u32.to_le_bytes(), "{ icinva(R2) }");      test_display(&0b0101_011_1110_00000_11_0_00000_000_00010u32.to_le_bytes(), "{ isync }"); @@ -305,6 +334,7 @@ fn inst_0110() {      test_display(&0b0110_0010010_00110_11_0_00100_011_01000u32.to_le_bytes(), "{ diag1(R7:6, R5:4) }");      test_display(&0b0110_0011001_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ C23:22 = R7:6 }"); +      test_display(&0b0110_1000000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ R23:22 = C7:6 }");      test_display(&0b0110_1001000_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ loop0($+#36, #0xd2) }"); @@ -313,7 +343,7 @@ fn inst_0110() {      test_display(&0b0110_1001110_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ P3 = sp2loop0($+#36, #0xd2) }");      test_display(&0b0110_1001111_00110_11_0_000101_00_01010u32.to_le_bytes(), "{ P3 = sp3loop0($+#36, #0xd2) }"); -    test_display(&0b0110_1010000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ R22 = C6 }"); +    test_display(&0b0110_1010000_00110_11_0_000101_00_10110u32.to_le_bytes(), "{ R22 = M0 }");      test_display(&0b0110_1010010_01001_11_0_000101_00_10110u32.to_le_bytes(), "{ R22 = add(pc, #0x5) }");      test_display(&0b0110_1011000_00011_11_0_000100_00_00001u32.to_le_bytes(), "{ P1 = and(P2, P3) }"); @@ -335,8 +365,6 @@ fn inst_0110() {      test_display(&0b0110_1011111_00011_11_0_000100_00_10001u32.to_le_bytes(), "{ P1 = or(P2, !P3) }");      test_display(&0b0110_1011111_10011_11_0_000100_00_10001u32.to_le_bytes(), "{ P1 = or(P3, or(P2, !P0)) }"); -    test_display(&0b0110_1100001_01001_11_0_000000_00_00000u32.to_le_bytes(), "{ barrier }"); -      test_display(&0b0110_1111111_01010_11_0_001100_10_00011u32.to_le_bytes(), "{ R3 = movlen(R6, R11:10) }");  } | 
