Exemplo n.º 1
0
        void IEmitter.Emit(ILGenerator methodIL, CpuInternalBuilders internals)
        {
            methodIL.Emit(OpCodes.Ldarg_0);
            switch (_opcode)
            {
            case 0x06:     // MVI B
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.B);
                break;

            case 0x0E:     // MVI C
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.C);
                break;

            case 0x16:     // MVI D
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.D);
                break;

            case 0x1E:     // MVI E
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.E);
                break;

            case 0x26:     // MVI H
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.H);
                break;

            case 0x2E:     // MVI L
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.L);
                break;

            case 0x36:     // MVI M
                methodIL.Emit(OpCodes.Ldfld, internals.MemoryBusField);
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Ldarg_0);
                methodIL.Emit(OpCodes.Call, internals.HL);
                methodIL.Emit(OpCodes.Callvirt, internals.MemoryBusField.FieldType.GetMethod("WriteByte") !);
                break;

            case 0x3E:     // MVI A
                methodIL.EmitLd8Immediate(_operand1);
                methodIL.Emit(OpCodes.Stfld, internals.A);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(_opcode),
                                                      $"MVI shouldn't be run for opcode byte {_opcode}");
            }
        }
        public void PostInstructionEmit(ILGenerator methodIL, CpuInternalBuilders internals, ushort programCounter)
        {
            // Check whether to fire half screen interrupt
            var skipInterrupt  = methodIL.DefineLabel();
            var skipHalfScreen = methodIL.DefineLabel();

            // Always decrement cycles to interrupt
            methodIL.Emit(OpCodes.Ldloc, _interruptDownCounter.LocalIndex);
            methodIL.Emit(OpCodes.Stloc, _oldInterruptDownCounter.LocalIndex);
            methodIL.Emit(OpCodes.Ldloc, _interruptDownCounter.LocalIndex);
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Ldfld, internals.CycleCounter);
            methodIL.Emit(OpCodes.Sub);
            methodIL.Emit(OpCodes.Stloc, _interruptDownCounter.LocalIndex);

            // Check if we've just crossed the half screen boundary
            methodIL.Emit(OpCodes.Ldloc, _interruptDownCounter.LocalIndex);
            methodIL.Emit(OpCodes.Ldc_I8, SpaceInvadersApplication.HalfCyclesPerScreen + 1);
            methodIL.Emit(OpCodes.Clt);
            methodIL.Emit(OpCodes.Ldloc, _oldInterruptDownCounter.LocalIndex);
            methodIL.Emit(OpCodes.Ldc_I8, SpaceInvadersApplication.HalfCyclesPerScreen);
            methodIL.Emit(OpCodes.Cgt);
            methodIL.Emit(OpCodes.And);
            methodIL.Emit(OpCodes.Brfalse, skipHalfScreen);
#if DEBUG
            methodIL.EmitWriteLine("Half screen interrupt");
#endif
            // Actually _do_ the half screen interrupt (RST 0)
            // If IE flag set then skip interrupt check
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Ldfld, internals.InterruptEnable);
            methodIL.Emit(OpCodes.Brfalse, skipInterrupt);
#if DEBUG
            methodIL.EmitWriteLine("Half screen interrupt EI enabled");
#endif
            var halfEmitter = new CallEmitter(0xCF, programCounter, internals.ProgramLabels[0x08], 0x08);
            halfEmitter.Emit(methodIL, internals);
            methodIL.Emit(OpCodes.Br, skipInterrupt);

            // Skipped the half screen so now check for full screen interrupt
            methodIL.MarkLabel(skipHalfScreen);

            methodIL.Emit(OpCodes.Ldc_I8, 0L);
            methodIL.Emit(OpCodes.Ldloc, _interruptDownCounter);
            methodIL.Emit(OpCodes.Blt, skipInterrupt);

#if DEBUG
            methodIL.EmitWriteLine("Full screen interrupt");
#endif

            // Fire the vblank routine on the renderer
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Ldfld, internals.MemoryBusField);
            methodIL.Emit(OpCodes.Callvirt, internals.RendererField.FieldType.GetMethod("VBlank") !);

            // Reset the interrupt down counter
            methodIL.Emit(OpCodes.Ldc_I8, SpaceInvadersApplication.CyclesPerScreen);
            methodIL.Emit(OpCodes.Stloc, _interruptDownCounter.LocalIndex);

            // Fire the vblank interrupt routine
            // If IE flag not set then skip interrupt fire (but still do vblank call)
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Ldfld, internals.InterruptEnable);
            methodIL.Emit(OpCodes.Brfalse, skipInterrupt);
            var fullEmitter = new CallEmitter(0xD7, programCounter, internals.ProgramLabels[0x10], 0x10);
            fullEmitter.Emit(methodIL, internals);

            methodIL.MarkLabel(skipInterrupt);
        }
Exemplo n.º 3
0
 public void PostInstructionEmit(ILGenerator methodIL, CpuInternalBuilders internals, ushort programCounter)
 {
 }