
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace PIC_Simulator.PIC
{
	class PICBefehl
	{
		public string befehl;
		public uint parameter_d;
		public uint parameter_f;
		public uint parameter_x;
		public uint parameter_k;
		public uint parameter_b;

		public int labelnummer;

		public int zeilennummer;
	}

	class PICProgramm
	{
		public const uint ADDR_INDF = 0x00;
		public const uint ADDR_TMR0 = 0x01;
		public const uint ADDR_PCL = 0x02;
		public const uint ADDR_STATUS = 0x03;
		public const uint ADDR_FSR = 0x04;
		public const uint ADDR_PORT_A = 0x05;
		public const uint ADDR_PORT_B = 0x06;
		public const uint ADDR_UNIMPL_A = 0x07;
		public const uint ADDR_PCLATH = 0x0A;
		public const uint ADDR_INTCON = 0x0B;

		public const uint ADDR_OPTION = 0x81;
		public const uint ADDR_TRIS_A = 0x85;
		public const uint ADDR_TRIS_B = 0x86;
		public const uint ADDR_UNIMPL_B = 0x87;
		public const uint ADDR_EECON1 = 0x88;
		public const uint ADDR_EECON2 = 0x89;

		public const uint STATUS_BIT_IRP = 7;		// Unused in PIC16C84
		public const uint STATUS_BIT_RP1 = 6;		// Register Bank Selection Bit [1] (Unused in PIC16C84)
		public const uint STATUS_BIT_RP0 = 5;		// Register Bank Selection Bit [0]
		public const uint STATUS_BIT_TO = 4;		// Time Out Bit
		public const uint STATUS_BIT_PD = 3;		// Power Down Bit
		public const uint STATUS_BIT_Z = 2;			// Zero Bit
		public const uint STATUS_BIT_DC = 1;		// Digit Carry Bit
		public const uint STATUS_BIT_C = 0;			// Carry Bit

		public const uint OPTION_BIT_RBPU = 7;		// PORT-B Pull-Up Enable Bit
		public const uint OPTION_BIT_INTEDG = 6;	// Interrupt Edge Select Bit
		public const uint OPTION_BIT_T0CS = 5;		// TMR0 Clock Source Select Bit
		public const uint OPTION_BIT_T0SE = 4;		// TMR0 Source Edge Select Bit
		public const uint OPTION_BIT_PSA = 3;		// Prescaler Alignment Bit
		public const uint OPTION_BIT_PS2 = 2;		// Prescaler Rate Select Bit [2]
		public const uint OPTION_BIT_PS1 = 1;		// Prescaler Rate Select Bit [1]
		public const uint OPTION_BIT_PS0 = 0;		// Prescaler Rate Select Bit [0]

		public const uint INTCON_BIT_GIE = 7;		// Global Interrupt Enable Bit
		public const uint INTCON_BIT_EEIE = 6;		// EE Write Complete Interrupt Enable Bit
		public const uint INTCON_BIT_T0IE = 5;		// TMR0 Overflow Interrupt Enable Bit
		public const uint INTCON_BIT_INTE = 4;		// RB0/INT Interrupt Bit
		public const uint INTCON_BIT_RBIE = 3;		// RB Port Change Interrupt Enable Bit
		public const uint INTCON_BIT_T0IF = 2;		// TMR0 Overflow Interrupt Flag Bit
		public const uint INTCON_BIT_INTF = 1;		// RB0/INT Interrupt Flag Bit
		public const uint INTCON_BIT_RBIF = 0;		// RB Port Change Interrupt Flag Bit


		public const string ADDWF  = "000111dfffffff";
		public const string ANDWF  = "000101dfffffff";
		public const string CLRF   = "0000011fffffff";
		public const string CLRW   = "0000010xxxxxxx";
		public const string COMF   = "001001dfffffff";
		public const string DECF   = "000011dfffffff";
		public const string DECFSZ = "001011dfffffff";
		public const string INCF   = "001010dfffffff";
		public const string INCFSZ = "001111dfffffff";
		public const string IORWF  = "000100dfffffff";
		public const string MOVF   = "001000dfffffff";
		public const string MOVWF  = "0000001fffffff";
		public const string NOP    = "0000000xx00000";
		public const string RLF    = "001101dfffffff";
		public const string RRF    = "001100dfffffff";
		public const string SUBWF  = "000010dfffffff";
		public const string SWAPF  = "001110dfffffff";
		public const string XORWF  = "000110dfffffff";

		public const string BCF    = "0100bbbfffffff";
		public const string BSF    = "0101bbbfffffff";
		public const string BTFSC  = "0110bbbfffffff";
		public const string BTFSS  = "0111bbbfffffff";
		
		public const string ADDLW  = "11111xkkkkkkkk";
		public const string ANDLW  = "111001kkkkkkkk";
		public const string CALL   = "100kkkkkkkkkkk";
		public const string CLRWDT = "00000001100100";
		public const string GOTO   = "101kkkkkkkkkkk";
		public const string IORLW  = "111000kkkkkkkk";
		public const string MOVLW  = "1100xxkkkkkkkk";
		public const string RETFIE = "00000000001001";
		public const string RETLW  = "1101xxkkkkkkkk";
		public const string RETURN = "00000000001000";
		public const string SLEEP  = "00000001100011";
		public const string SUBLW  = "11110xkkkkkkkk";
		public const string XORLW  = "111010kkkkkkkk";

		public string[] ALL_COMMANDS = {ADDWF, ANDWF, CLRF, CLRW, COMF, DECF, DECFSZ, INCF, INCFSZ, IORWF, MOVF, MOVWF, NOP, RLF, RRF, SUBWF, SWAPF, XORWF, BCF, BSF, BTFSC, BTFSS, ADDLW, ANDLW, CALL, CLRWDT, GOTO, IORLW, MOVLW, RETFIE, RETLW, RETURN, SLEEP, SUBLW, XORLW  };

		public List<PICBefehl> befehle;

		public int PCCounter = 0; // -> nächster befehl
		public int Stepcount = 0;
		public uint Register_W = 0;
		public uint[] Register = new uint[0x100];
		public Stack<uint> Stack = new Stack<uint>();
		public bool IsSleeping = false;

		public List<int> Breakpoints = new List<int>(); 

		public PICProgramm()
		{
			
		}

		public void Laden(string code)
		{
			befehle = new List<PICBefehl>();

			int zn = -1;
			foreach (var zeile in Regex.Split(code, @"\r?\n"))
			{
				zn++;

				if (zeile.StartsWith("         ")) continue;
				if (zeile.Length < 10) continue;

				befehle.Add(FindeBefehl(zeile, zn));
			}
		}

		private PICBefehl FindeBefehl(string zeile, int zeilennummer)
		{
			foreach (var cmd in ALL_COMMANDS)
			{
				string bin = hex2binary(zeile.Substring(5, 4));

				uint p_d = 0;
				uint p_f = 0;
				uint p_x = 0;
				uint p_k = 0;
				uint p_b = 0;

				bool ok = true;

				for (int i = 0; i < 14; i++)
				{
					if (cmd[i] == '0' && bin[i] == '0') continue;
					if (cmd[i] == '1' && bin[i] == '1') continue;
					if (cmd[i] == 'd' && bin[i] == '0') { p_d <<= 1; p_d |= 0; continue; }
					if (cmd[i] == 'd' && bin[i] == '1') { p_d <<= 1; p_d |= 1; continue; }
					if (cmd[i] == 'f' && bin[i] == '0') { p_f <<= 1; p_f |= 0; continue; }
					if (cmd[i] == 'f' && bin[i] == '1') { p_f <<= 1; p_f |= 1; continue; }
					if (cmd[i] == 'x' && bin[i] == '0') { p_x <<= 1; p_x |= 0; continue; }
					if (cmd[i] == 'x' && bin[i] == '1') { p_x <<= 1; p_x |= 1; continue; }
					if (cmd[i] == 'k' && bin[i] == '0') { p_k <<= 1; p_k |= 0; continue; }
					if (cmd[i] == 'k' && bin[i] == '1') { p_k <<= 1; p_k |= 1; continue; }
					if (cmd[i] == 'b' && bin[i] == '0') { p_b <<= 1; p_b |= 0; continue; }
					if (cmd[i] == 'b' && bin[i] == '1') { p_b <<= 1; p_b |= 1; continue; }
					if (cmd[i] == '0' && bin[i] == '1') { ok = false; break; }
					if (cmd[i] == '1' && bin[i] == '0') { ok = false; continue; }

					throw new Exception("Falscher wert in cmd");
				}

				if (ok)
				{
					PICBefehl b = new PICBefehl();
					b.befehl = cmd;
					b.parameter_d = p_d;
					b.parameter_f = p_f;
					b.parameter_k = p_k;
					b.parameter_x = p_x;
					b.parameter_b = p_b;
					b.zeilennummer = zeilennummer;
					b.labelnummer = Convert.ToInt32(zeile.Substring(0, 4), 16);
					return b;
				}
			}

			throw new Exception("konnte befehl nicht finden: " + zeile);
		}

		private string hex2binary(string hexvalue)
		{
			string binaryval = "";
			binaryval = Convert.ToString(Convert.ToInt32(hexvalue, 16), 2).PadLeft(14, '0');
			return binaryval;
		}

		public bool Step()
		{
			if (PCCounter >= befehle.Count) return true;

			PICBefehl aktueller_befehl = befehle[PCCounter];

			if (IsSleeping) return false;

			if (aktueller_befehl.befehl == ADDWF)
			{
				// Add the contents of the W register with
				// register 'f'.If 'd' is 0 the result is stored
				// in the W register.If 'd' is 1 the result is
				// stored back in register 'f'.

				uint a = GetRegister(aktueller_befehl.parameter_f);
				uint b = Register_W;

				uint Result = a + b;
				bool dc = AdditionDigitCarry(a, b);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, (Result % 0x100) == 0);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_DC, dc);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, Result > 0xFF);

				Result %= 0x100;

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == ANDWF)
			{
				// AND the W register with register 'f'.If 'd'
				// is 0 the result is stored in the W regis -
				// ter.If 'd' is 1 the result is stored back in
				// register 'f'

				uint Result = Register_W & GetRegister(aktueller_befehl.parameter_f);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == CLRF)
			{
				// The contents of register 'f' are cleared
				// and the Z bit is set.

				SetRegister(aktueller_befehl.parameter_f, 0x00);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, true);
			}
			else if (aktueller_befehl.befehl == CLRW)
			{
				// W register is cleared.Zero bit (Z) is
				// set.

			   Register_W = 0;
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, true);
			}
			else if (aktueller_befehl.befehl == COMF)
			{
				// The contents of register 'f' are comple-
				// mented.If 'd' is 0 the result is stored in
				// W.If 'd' is 1 the result is stored back in
				// register 'f'.

				uint Result = ~GetRegister(aktueller_befehl.parameter_f);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == DECF)
			{
				// Decrement register 'f'.If 'd' is 0 the
				// result is stored in the W register.If 'd' is
				// 1 the result is stored back in register 'f'.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				if (Result == 0)
					Result = 0xFF;
				else
					Result -= 1;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == DECFSZ)
			{
				// The contents of register 'f' are decre-
				// mented.If 'd' is 0 the result is placed in the
				// W register.If 'd' is 1 the result is placed
				// back in register 'f'.
				// If the result is 1, the next instruction, is
				// executed.If the result is 0, then a NOP is
				// executed instead making it a 2T CY instruc -
				// tion.

				bool Cond = GetRegister(aktueller_befehl.parameter_f) == 1;

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				if (Result == 0)
					Result = 0xFF;
				else
					Result -= 1;

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;

				if (Cond)
				{
					PCCounter++; // skip next
				}
			}
			else if (aktueller_befehl.befehl == INCF)
			{
				// The contents of register 'f' are incre-
				// mented.If 'd' is 0 the result is placed in
				// the W register.If 'd' is 1 the result is
				// placed back in register 'f'.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				Result += 1;

				Result %= 0x100;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == INCFSZ)
			{
				// The contents of register 'f' are incre-
				// mented.If 'd' is 0 the result is placed in
				// the W register.If 'd' is 1 the result is
				// placed back in register 'f'.
				// If the result is 1, the next instruction is
				// executed.If the result is 0, a NOP is exe -
				// cuted instead making it a 2T CY instruc -
				// tion

				bool Cond = GetRegister(aktueller_befehl.parameter_f) == 0xFF;

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				Result += 1;

				Result %= 0x100;

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;

				if (Cond)
				{
					PCCounter++; // skip next
				}
			}
			else if (aktueller_befehl.befehl == IORWF)
			{
				// Inclusive OR the W register with regis -
				// ter 'f'.If 'd' is 0 the result is placed in the
				// W register.If 'd' is 1 the result is placed
				// back in register 'f'.

				uint Result = Register_W | GetRegister(aktueller_befehl.parameter_f);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == MOVF)
			{
				// The contents of register f is moved to a
				// destination dependant upon the status
				// of d. If d = 0, destination is W register. If
				// d = 1, the destination is file register f
				// itself.d = 1 is useful to test a file regis-
				// ter since status flag Z is affected.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == MOVWF)
			{
				// Move data from W register to register
				// 'f'

				SetRegister(aktueller_befehl.parameter_f, Register_W);
			}
			else if (aktueller_befehl.befehl == NOP)
			{
				//No operation.
			}
			else if (aktueller_befehl.befehl == RLF)
			{
				// The contents of register 'f' are rotated
				// one bit to the left through the Carry
				// Flag.If 'd' is 0 the result is placed in the
				// W register.If 'd' is 1 the result is stored
				// back in register 'f'.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				uint Carry_Old = GetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C) ? 1u : 0u;
				uint Carry_New = (Result & 0x80) >> 7;

				Result = Result << 1;
				Result &= 0xFF;

				Result |= Carry_Old;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, Carry_New != 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == RRF)
			{
				// The contents of register 'f' are rotated
				// one bit to the right through the Carry
				// Flag.If 'd' is 0 the result is placed in the
				// W register.If 'd' is 1 the result is placed
				// back in register 'f'.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				uint Carry_Old = GetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C) ? 0x80u : 0x00u;
				uint Carry_New = Result & 0x01;

				Result = Result >> 1;
				Result &= 0xFF;

				Result |= Carry_Old;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, Carry_New != 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == SUBWF)
			{
				// Subtract(2’s complement method) W reg-
				// ister from register 'f'.If 'd' is 0 the result is
				// stored in the W register.If 'd' is 1 the
				// result is stored back in register 'f'.

				uint a = GetRegister(aktueller_befehl.parameter_f);
				uint b = Register_W;

				bool carry;

				bool dc = SubtractionDigitCarry(a, b);

				if (carry = a < b)
				{
					a += 0x100;
				}

				uint Result = a - b;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, (Result % 0x100) == 0);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_DC, dc);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, !carry);

				Result %= 0x100;

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == SWAPF)
			{
				// The upper and lower nibbles of register
				// 'f' are exchanged. If 'd' is 0 the result is
				// placed in W register. If 'd' is 1 the result
				// is placed in register 'f'.

				uint Result = GetRegister(aktueller_befehl.parameter_f);

				uint Low = Result & 0x0F;
				uint High = Result & 0xF0;

				Result = (Low << 4) | (High >> 4);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == XORWF)
			{
				// Exclusive OR the contents of the W
				// register with register 'f'.If 'd' is 0 the
				// result is stored in the W register.If 'd' is
				// 1 the result is stored back in register 'f'.

				uint Result = Register_W ^ GetRegister(aktueller_befehl.parameter_f);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				if (aktueller_befehl.parameter_d != 0)
					SetRegister(aktueller_befehl.parameter_f, Result);
				else
					Register_W = Result;
			}
			else if (aktueller_befehl.befehl == BCF)
			{
				// Bit 'b' in register 'f' is cleared 

				SetRegister(aktueller_befehl.parameter_f, aktueller_befehl.parameter_b, false);
			}
			else if (aktueller_befehl.befehl == BSF)
			{
				// Bit 'b' in register 'f' is set.

				SetRegister(aktueller_befehl.parameter_f, aktueller_befehl.parameter_b, true);
			}
			else if (aktueller_befehl.befehl == BTFSC)
			{
				// If bit 'b' in register 'f' is '1' then the next
				// instruction is executed.
				// If bit 'b', in register 'f', is '0' then the next
				// instruction is discarded, and a NOP is
				// executed instead, making this a 2T CY
				// instruction

				if (!GetBit(GetRegister(aktueller_befehl.parameter_f), aktueller_befehl.parameter_b))
				{
					PCCounter++;
				}
			}
			else if (aktueller_befehl.befehl == BTFSS)
			{
				// If bit 'b' in register 'f' is '0' then the next
				// instruction is executed.
				// If bit 'b' is '1', then the next instruction is
				// discarded and a NOP is executed
				// instead, making this a 2T CY instruction.

				if (GetBit(GetRegister(aktueller_befehl.parameter_f), aktueller_befehl.parameter_b))
				{
					PCCounter++;
				}
			}
			else if (aktueller_befehl.befehl == ADDLW)
			{
				// The contents of the W register are
				// added to the eight bit literal 'k' and the
				// result is placed in the W register

				uint a = Register_W;
				uint b = aktueller_befehl.parameter_k;

				uint Result = a + b;
				bool dc = AdditionDigitCarry(a, b);

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, (Result % 0x100) == 0);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_DC, dc);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, Result > 0xFF);

				Result %= 0x100;

				Register_W = Result;
			}
			else if (aktueller_befehl.befehl == ANDLW)
			{
				// The contents of W register are
				// AND’ed with the eight bit literal 'k'.The
				// result is placed in the W register

				uint Result = Register_W & aktueller_befehl.parameter_k;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				Register_W = Result;
			}
			else if (aktueller_befehl.befehl == CALL)
			{
				// Call Subroutine. First, return address
				// (PC + 1) is pushed onto the stack. The
				// eleven bit immediate address is loaded
				// into PC bits<10:0 >.The upper bits of
				// the PC are loaded from PCLATH.CALL
				// is a two cycle instruction.

				Stack.Push((uint) PCCounter);
				PCCounter = (int) (aktueller_befehl.parameter_k - 1);
			}
			else if (aktueller_befehl.befehl == CLRWDT)
			{
				// CLRWDT instruction resets the Watch -
				// dog Timer.It also resets the prescaler
				// of the WDT. Status bits TO and PD are
				// set.

				//TODO
			}
			else if (aktueller_befehl.befehl == GOTO)
			{
				// GOTO is an unconditional branch.The
				// eleven bit immediate value is loaded
				// into PC bits<10:0>.The upper bits of
				// PC are loaded from PCLATH<4:3>.
				// GOTO is a two cycle instruction.

				PCCounter = befehle.FindIndex(b => b.labelnummer == aktueller_befehl.parameter_k) - 1;
			}
			else if (aktueller_befehl.befehl == IORLW)
			{
				// The contents of the W register is
				// OR’ed with the eight bit literal 'k'.The
				// result is placed in the W register

				uint Result = Register_W | aktueller_befehl.parameter_k;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				Register_W = Result;
			}
			else if (aktueller_befehl.befehl == MOVLW)
			{
				// The eight bit literal 'k' is loaded into W
				// register.The don’t cares will assemble
				// as 0’s.

				Register_W = aktueller_befehl.parameter_k;
			}
			else if (aktueller_befehl.befehl == RETFIE)
			{
				// Return from Interrupt.Stack is POPed
				// and Top of Stack(TOS) is loaded in the
				// PC.Interrupts are enabled by setting
				// Global Interrupt Enable bit, GIE
				// (INTCON < 7 >).This is a two cycle
				// instruction.

				//TODO
			}
			else if (aktueller_befehl.befehl == RETLW)
			{
				// The W register is loaded with the eight
				// bit literal 'k'.The program counter is
				// loaded from the top of the stack(the
				// return address). This is a two cycle
				// instruction.
				Register_W = aktueller_befehl.parameter_k;
				PCCounter = (int) Stack.Pop();
			}
			else if (aktueller_befehl.befehl == RETURN)
			{
				// Return from subroutine. The stack is
				// POPed and the top of the stack(TOS)
				// is loaded into the program counter.This
				// is a two cycle instruction.
				PCCounter = (int)Stack.Pop();
			}
			else if (aktueller_befehl.befehl == SLEEP)
			{
				// The power-down status bit, PD is
				// cleared.Time -out status bit, TO is
				// set.Watchdog Timer and its prescaler
				// are cleared.
				// The processor is put into SLEEP
				// mode with the oscillator stopped. See
				// Section 14.8 for more details.

				if (GetRegisterOhneBank(ADDR_OPTION, OPTION_BIT_PSA))
				{
					SetRegisterOhneBank(ADDR_OPTION, OPTION_BIT_PS0, false);
					SetRegisterOhneBank(ADDR_OPTION, OPTION_BIT_PS1, false);
					SetRegisterOhneBank(ADDR_OPTION, OPTION_BIT_PS2, false);
				}

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_TO, true);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_PD, false);

				IsSleeping = true;
			}
			else if (aktueller_befehl.befehl == SUBLW)
			{
				// The W register is subtracted (2’s comple-
				// ment method) from the eight bit literal 'k'.
				// The result is placed in the W register.

				uint a = aktueller_befehl.parameter_k;
				uint b = Register_W;

				bool carry;

				bool dc = SubtractionDigitCarry(a, b);

				if (carry = a < b)
				{
					a += 0x100;
				}

				uint Result = a - b;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, (Result % 0x100) == 0);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_DC, dc);
				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_C, !carry);

				Result %= 0x100;

				Register_W = Result;
			}
			else if (aktueller_befehl.befehl == XORLW)
			{
				// The contents of the W register are
				// XOR’ed with the eight bit literal 'k'.
				// The result is placed in the W regis -
				// ter.

				uint Result = Register_W ^ aktueller_befehl.parameter_k;

				SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, Result == 0);

				Register_W = Result; ;
			}

			PCCounter++;
			Stepcount++;

			return PCCounter >= befehle.Count;
		}

		public void SetRegisterOhneBank(uint index, uint wert)
		{
			// register die nur einmal auf bank1 + 2 existieren
			if (index == ADDR_PCL + 0x80) index -= 0x80;
			if (index == ADDR_STATUS + 0x80) index -= 0x80;
			if (index == ADDR_FSR + 0x80) index -= 0x80;
			if (index == ADDR_PCLATH + 0x80) index -= 0x80;
			if (index == ADDR_INTCON + 0x80) index -= 0x80;

			if (index == ADDR_PCL) // PC direkt setzen
			{
				wert &= 0xFF; // Only Low 8 Bit
				uint high = GetRegister(ADDR_PCLATH);
				high &= 0x1F; // Only Bit <0,1,2,3,4>
				high <<= 8;

				PCCounter = (int) (high | wert) - 1;
			}

			Register[index] = wert;
		}

		public uint GetRegisterOhneBank(uint index)
		{
			if (index == ADDR_UNIMPL_A) return 0;
			if (index == ADDR_UNIMPL_B) return 0;

			// register die nur einmal auf bank1 + 2 existieren
			if (index == ADDR_PCL + 0x80) index -= 0x80;
			if (index == ADDR_STATUS + 0x80) index -= 0x80;
			if (index == ADDR_FSR + 0x80) index -= 0x80;
			if (index == ADDR_PCLATH + 0x80) index -= 0x80;
			if (index == ADDR_INTCON + 0x80) index -= 0x80;

			return Register[index];
		}

		private uint GetRegister(uint index)
		{
			if ((Register[ADDR_STATUS] & STATUS_BIT_RP0) == STATUS_BIT_RP0)
			{
				return GetRegisterOhneBank(0x80 + index);
			}
			else
			{
				return GetRegisterOhneBank(index);
			}
		}

		private void SetRegister(uint index, uint wert)
		{
			if ((Register[ADDR_STATUS] & STATUS_BIT_RP0) == STATUS_BIT_RP0)
			{
				SetRegisterOhneBank(0x80 + index, wert);
			}
			else
			{
				SetRegisterOhneBank(index, wert);
			}
		}

		public void SetRegisterOhneBank(uint index, uint bit, bool wert)
		{
			SetRegisterOhneBank(index, SetBit(GetRegisterOhneBank(index), bit, wert));
		}


		private void SetRegister(uint index, uint bit, bool wert)
		{
			SetRegister(index, SetBit(GetRegister(index), bit, wert));
		}

		public bool GetRegisterOhneBank(uint index, uint bit)
		{
			return GetBit(GetRegisterOhneBank(index), bit);
		}

		public static bool AdditionDigitCarry(uint a, uint b)
		{
			a &= 0x0F;
			b &= 0x0F;

			return (a + b) > 0x0F;
		}

		public static bool SubtractionDigitCarry(uint a, uint b)
		{
			b = (~b) + 1;

			return AdditionDigitCarry(a, b);
		}

		public static bool GetBit(uint val, uint pos)
		{
			return (val & SHL(1, pos)) != 0;
		}

		public static uint SHL(uint val, uint steps)
		{
			return (uint)((val) << ((int)steps));
		}

		public static uint SHR(uint val, uint steps)
		{
			return (uint)((val) >> ((int)steps));
		}

		public static uint SetBit(uint val, uint pos, bool bit)
		{
			return bit ? (val | SHL(1, pos)) : (val & ~SHL(1, pos));
		}

	}
}
