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 befehle; public int PCCounter = 0; // -> nächster befehl public int Stepcount = 0; public uint Register_W = 0; public uint[] Register = new uint[0x100]; public PICProgramm() { } public void Laden(string code) { befehle = new List(); 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 (aktueller_befehl.befehl == ADDWF) { 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) { 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) { SetRegister(aktueller_befehl.parameter_f, 0x00); SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, true); } else if (aktueller_befehl.befehl == CLRW) { Register_W = 0; SetRegisterOhneBank(ADDR_STATUS, STATUS_BIT_Z, true); } else if (aktueller_befehl.befehl == COMF) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { SetRegister(aktueller_befehl.parameter_f, Register_W); } else if (aktueller_befehl.befehl == NOP) { // ~~~~~ } else if (aktueller_befehl.befehl == RLF) { 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) { 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) { 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) { 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) { 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) { SetRegister(aktueller_befehl.parameter_f, aktueller_befehl.parameter_b, false); } else if (aktueller_befehl.befehl == BSF) { SetRegister(aktueller_befehl.parameter_f, aktueller_befehl.parameter_b, true); } else if (aktueller_befehl.befehl == BTFSC) { if (!GetBit(GetRegister(aktueller_befehl.parameter_f), aktueller_befehl.parameter_b)) { PCCounter++; } } else if (aktueller_befehl.befehl == BTFSS) { if (GetBit(GetRegister(aktueller_befehl.parameter_f), aktueller_befehl.parameter_b)) { PCCounter++; } } else if (aktueller_befehl.befehl == ADDLW) { 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) { 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) { //TODO } else if (aktueller_befehl.befehl == CLRWDT) { //TODO } else if (aktueller_befehl.befehl == GOTO) { PCCounter = befehle.FindIndex(b => b.labelnummer == aktueller_befehl.parameter_k) - 1; } else if (aktueller_befehl.befehl == IORLW) { 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) { Register_W = aktueller_befehl.parameter_k; } else if (aktueller_befehl.befehl == RETFIE) { //TODO } else if (aktueller_befehl.befehl == RETLW) { //TODO } else if (aktueller_befehl.befehl == RETURN) { //TODO } else if (aktueller_befehl.befehl == SLEEP) { //TODO } else if (aktueller_befehl.befehl == SUBLW) { 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) { 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; } private uint GetRegister(uint index) { if ((Register[ADDR_STATUS] & STATUS_BIT_RP0) == STATUS_BIT_RP0) { return Register[0x80 + index]; } else { return Register[index]; } } private void SetRegister(uint index, uint wert) { if ((Register[ADDR_STATUS] & STATUS_BIT_RP0) == STATUS_BIT_RP0) { Register[0x80 + index] = wert; } else { Register[index] = wert; } } private void SetRegister(uint index, uint bit, bool wert) { if ((Register[ADDR_STATUS] & STATUS_BIT_RP0) == STATUS_BIT_RP0) { Register[0x80 + index] = SetBit(Register[index], bit, wert); } else { Register[index] = SetBit(Register[index], bit, wert); } } private void SetRegisterOhneBank(uint index, uint bit, bool wert) { Register[index] = SetBit(Register[index], bit, wert); } public bool GetRegisterOhneBank(uint index, uint bit) { return GetBit(Register[index], bit); } public uint GetRegisterOhneBank(uint index) { return Register[index]; } 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)); } } }