Handle special cases for CP0 register writes.

- The timer interrupt is cleared on writes to the Compare register (see: #6.3.4).
- Only software interrupt bits are writable into the Cause register (see: #6.3.6).
master
Nabile Rahmani 2018-12-24 21:38:18 +01:00
parent bb4d756ebb
commit a4d06cef67
2 changed files with 23 additions and 2 deletions

View File

@ -21,6 +21,7 @@ namespace DotN64.CPU
ce = BitVector32.CreateSection((1 << 2) - 1, constant2),
constant3 = BitVector32.CreateSection(1, ce),
bd = BitVector32.CreateSection(1, constant3);
public static readonly ulong WriteMask = (ulong)(InterruptPending.WriteMask << ip.Offset);
#endregion
#region Properties
@ -80,9 +81,10 @@ namespace DotN64.CPU
#region Fields
private BitVector32 bits;
private static BitVector32.Section softwareInterrupts = BitVector32.CreateSection((1 << 2) - 1),
private static readonly BitVector32.Section softwareInterrupts = BitVector32.CreateSection((1 << 2) - 1),
externalNormalInterrupts = BitVector32.CreateSection((1 << 5) - 1, softwareInterrupts),
timerInterrupt = BitVector32.CreateSection(1, externalNormalInterrupts);
public static readonly byte WriteMask = (byte)(softwareInterrupts.Mask << softwareInterrupts.Offset);
#endregion
#region Properties

View File

@ -34,7 +34,26 @@ namespace DotN64.CPU
Cause = new CauseRegister(this);
operations = new Dictionary<Instruction, Action<Instruction>>
{
[From(OpCode.MT)] = i => Registers[i.RD] = cpu.GPR[i.RT],
[From(OpCode.MT)] = i =>
{
var destination = i.RD;
var data = cpu.GPR[i.RT];
switch ((RegisterIndex)destination)
{
case RegisterIndex.Cause:
Registers[destination] &= ~CauseRegister.WriteMask;
Registers[destination] |= data & CauseRegister.WriteMask;
return;
case RegisterIndex.Compare:
var ip = Cause.IP;
ip.TimerInterrupt = false;
Cause.IP = ip;
break;
}
Registers[destination] = data;
},
[From(OpCode.MF)] = i => cpu.GPR[i.RT] = (ulong)(int)Registers[i.RD],
[From(FunctOpCode.TLBWI)] = i => { /* TODO. */ },
[From(FunctOpCode.ERET)] = i =>