Files
Yaroze.NET/src/Yaroze.Core/CPU/Instruction.cs
T
2026-01-24 17:23:50 +01:00

210 lines
5.9 KiB
C#

using Yaroze.Core.Utilities;
namespace Yaroze.Core.CPU;
/// <summary>
/// Represents a decoded MIPS instruction.
/// Provides methods to extract fields from the 32-bit instruction word.
/// </summary>
public readonly struct Instruction
{
private readonly uint _raw;
public Instruction(uint raw)
{
_raw = raw;
}
/// <summary>
/// Raw 32-bit instruction word.
/// </summary>
public uint Raw => _raw;
/// <summary>
/// Opcode (bits 31-26).
/// </summary>
public uint Opcode => BitUtils.ExtractBits(_raw, 26, 6);
/// <summary>
/// RS register field (bits 25-21).
/// </summary>
public uint Rs => BitUtils.ExtractBits(_raw, 21, 5);
/// <summary>
/// RT register field (bits 20-16).
/// </summary>
public uint Rt => BitUtils.ExtractBits(_raw, 16, 5);
/// <summary>
/// RD register field (bits 15-11).
/// </summary>
public uint Rd => BitUtils.ExtractBits(_raw, 11, 5);
/// <summary>
/// Shift amount field (bits 10-6).
/// </summary>
public uint Shamt => BitUtils.ExtractBits(_raw, 6, 5);
/// <summary>
/// Function code (bits 5-0).
/// </summary>
public uint Funct => BitUtils.ExtractBits(_raw, 0, 6);
/// <summary>
/// 16-bit immediate value (bits 15-0).
/// </summary>
public ushort Imm16 => (ushort)BitUtils.ExtractBits(_raw, 0, 16);
/// <summary>
/// 26-bit jump target (bits 25-0).
/// </summary>
public uint Target26 => BitUtils.ExtractBits(_raw, 0, 26);
/// <summary>
/// Sign-extended immediate value (for arithmetic/load/store).
/// </summary>
public uint ImmSigned => SignExtension.SignExtend16(Imm16);
/// <summary>
/// Zero-extended immediate value (for logic operations).
/// </summary>
public uint ImmUnsigned => Imm16;
/// <summary>
/// Coprocessor opcode (bits 25-21) for COP instructions.
/// </summary>
public uint CopOp => BitUtils.ExtractBits(_raw, 21, 5);
/// <summary>
/// Calculate branch target address.
/// </summary>
public uint BranchTarget(uint pc)
{
// Sign-extend 16-bit offset, shift left 2 bits, add to PC+4
uint offset = SignExtension.SignExtend16(Imm16) << 2;
return (pc + 4) + offset;
}
/// <summary>
/// Calculate jump target address.
/// </summary>
public uint JumpTarget(uint pc)
{
// Take upper 4 bits of PC+4, concatenate with target26 << 2
return (pc & 0xF0000000) | (Target26 << 2);
}
/// <summary>
/// Check if this is a NOP instruction (SLL $0, $0, 0).
/// </summary>
public bool IsNop => _raw == 0x00000000;
public override string ToString()
{
return $"0x{_raw:X8} [op={Opcode:X2} rs={Rs} rt={Rt} rd={Rd} funct={Funct:X2}]";
}
}
/// <summary>
/// MIPS instruction opcodes.
/// </summary>
public static class Opcode
{
public const uint SPECIAL = 0x00; // R-type instructions (use funct field)
public const uint REGIMM = 0x01; // Branch instructions (use rt field)
public const uint J = 0x02;
public const uint JAL = 0x03;
public const uint BEQ = 0x04;
public const uint BNE = 0x05;
public const uint BLEZ = 0x06;
public const uint BGTZ = 0x07;
public const uint ADDI = 0x08;
public const uint ADDIU = 0x09;
public const uint SLTI = 0x0A;
public const uint SLTIU = 0x0B;
public const uint ANDI = 0x0C;
public const uint ORI = 0x0D;
public const uint XORI = 0x0E;
public const uint LUI = 0x0F;
public const uint COP0 = 0x10;
public const uint COP1 = 0x11;
public const uint COP2 = 0x12;
public const uint COP3 = 0x13;
public const uint LB = 0x20;
public const uint LH = 0x21;
public const uint LWL = 0x22;
public const uint LW = 0x23;
public const uint LBU = 0x24;
public const uint LHU = 0x25;
public const uint LWR = 0x26;
public const uint SB = 0x28;
public const uint SH = 0x29;
public const uint SWL = 0x2A;
public const uint SW = 0x2B;
public const uint SWR = 0x2E;
public const uint LWC0 = 0x30;
public const uint LWC1 = 0x31;
public const uint LWC2 = 0x32;
public const uint LWC3 = 0x33;
public const uint SWC0 = 0x38;
public const uint SWC1 = 0x39;
public const uint SWC2 = 0x3A;
public const uint SWC3 = 0x3B;
}
/// <summary>
/// MIPS SPECIAL (R-type) function codes.
/// </summary>
public static class Funct
{
public const uint SLL = 0x00;
public const uint SRL = 0x02;
public const uint SRA = 0x03;
public const uint SLLV = 0x04;
public const uint SRLV = 0x06;
public const uint SRAV = 0x07;
public const uint JR = 0x08;
public const uint JALR = 0x09;
public const uint SYSCALL = 0x0C;
public const uint BREAK = 0x0D;
public const uint MFHI = 0x10;
public const uint MTHI = 0x11;
public const uint MFLO = 0x12;
public const uint MTLO = 0x13;
public const uint MULT = 0x18;
public const uint MULTU = 0x19;
public const uint DIV = 0x1A;
public const uint DIVU = 0x1B;
public const uint ADD = 0x20;
public const uint ADDU = 0x21;
public const uint SUB = 0x22;
public const uint SUBU = 0x23;
public const uint AND = 0x24;
public const uint OR = 0x25;
public const uint XOR = 0x26;
public const uint NOR = 0x27;
public const uint SLT = 0x2A;
public const uint SLTU = 0x2B;
}
/// <summary>
/// REGIMM branch types (rt field determines type).
/// </summary>
public static class RegImmRt
{
public const uint BLTZ = 0x00;
public const uint BGEZ = 0x01;
public const uint BLTZAL = 0x10;
public const uint BGEZAL = 0x11;
}
/// <summary>
/// COP0 function codes (rs field determines type for COP0 instructions).
/// </summary>
public static class COP0Funct
{
public const uint MFC0 = 0x00; // Move From COP0
public const uint MTC0 = 0x04; // Move To COP0
public const uint RFE = 0x10; // Return From Exception
}