import sys from enum import Enum class PIC16F84Emulator: def __init__(self): # Speicher self.flash = [0] * 1024 # Programmspeicher (1024 Worte) self.ram = [0] * 68 # Daten-RAM (0x0C bis 0x4F) self.eeprom = [0] * 64 # EEPROM-Daten # Register self.w = 0 # Arbeitsregister self.pc = 0 # Program Counter self.pclath = 0 # PCLATH Register self.status = 0 # STATUS Register self.option = 0 # OPTION Register self.intcon = 0 # INTCON Register # Status-Bits self.C = 0 # Carry Bit self.DC = 0 # Digit Carry Bit self.Z = 0 # Zero Bit self.PD = 1 # Power Down Bit self.TO = 1 # Time Out Bit # Stack self.stack = [0] * 8 self.stack_ptr = 0 # Betriebszustand self.running = True self.cycle_count = 0 def get_ram_address(self, address): """Berechnet die tatsächliche RAM-Adresse mit Banking""" bank = (self.status >> 5) & 0x01 if address < 0x0C: if bank == 0: return address # Special Function Registers Bank 0 else: return address + 0x80 # Special Function Registers Bank 1 elif address < 0x4F: return address # General Purpose RAM else: return address # Jenseits des gültigen Bereichs def write_ram(self, address, value): """Schreibt in den RAM mit Banking-Unterstützung""" if address < 0x0C: # Special Function Register addr = self.get_ram_address(address) if addr == 0x03: # STATUS self.status = value & 0xDF # Bit 5 nicht beschreibbar elif addr == 0x0A: # PCLATH self.pclath = value elif addr == 0x0B: # INTCON self.intcon = value else: self.ram[addr] = value & 0xFF else: self.ram[address] = value & 0xFF def read_ram(self, address): """Liest aus dem RAM mit Banking-Unterstützung""" if address < 0x0C: addr = self.get_ram_address(address) if addr == 0x03: # STATUS return self.status elif addr == 0x0A: # PCLATH return self.pclath elif addr == 0x0B: # INTCON return self.intcon else: return self.ram[addr] else: return self.ram[address] def update_status(self, result): """Aktualisiert die Zero-Flag basierend auf dem Ergebnis""" self.Z = 1 if (result & 0xFF) == 0 else 0 # Status-Register Bits setzen self.status = (self.status & 0xC0) | (self.C << 0) | (self.DC << 1) | (self.Z << 2) | (self.PD << 3) | (self.TO << 4) def execute_instruction(self, opcode): """Führt einen Befehl aus""" instruction = opcode & 0x3FFF # 14-Bit Befehl # Befehl dekodieren op = (instruction >> 13) & 0x07 # Oberste 3 Bits (0-7) if op == 0: # Byte-orientierte Operationen return self.execute_byte_instruction(instruction) elif op == 1: # Byte-orientierte Operationen mit '1' im MSB return self.execute_byte_instruction(instruction) elif op == 2: # Bit-orientierte Operationen return self.execute_bit_instruction(instruction) elif op == 3: # Bit-orientierte Operationen return self.execute_bit_instruction(instruction) elif op == 4: # Literal-Operationen return self.execute_literal_instruction(instruction) elif op == 5: # Literal-Operationen return self.execute_literal_instruction(instruction) elif op == 6: # Kontrolloperationen return self.execute_control_instruction(instruction) elif op == 7: # Kontrolloperationen return self.execute_control_instruction(instruction) return True def execute_byte_instruction(self, instruction): """Führt Byte-orientierte Befehle aus""" d = (instruction >> 7) & 0x01 # Destination (0=W, 1=f) f = instruction & 0x7F # File Register Address opcode = (instruction >> 9) & 0x0F value = self.read_ram(f) if opcode == 0x00: # ADDWF f,d result = self.w + value self.C = 1 if result > 0xFF else 0 self.DC = 1 if ((self.w & 0x0F) + (value & 0x0F)) > 0x0F else 0 result &= 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x01: # ANDWF f,d result = self.w & value self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x02: # CLRF f self.write_ram(f, 0) self.Z = 1 self.update_status(0) elif opcode == 0x03: # CLRW self.w = 0 self.Z = 1 self.update_status(0) elif opcode == 0x04: # COMF f,d result = (~value) & 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x05: # DECF f,d result = (value - 1) & 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x06: # DECFSZ f,d result = (value - 1) & 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) return result == 0 # Skip next instruction if zero elif opcode == 0x07: # INCF f,d result = (value + 1) & 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x08: # INCFSZ f,d result = (value + 1) & 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) return result == 0 # Skip next instruction if zero elif opcode == 0x09: # IORWF f,d result = self.w | value self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x0A: # MOVF f,d result = value self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x0B: # MOVWF f self.write_ram(f, self.w) elif opcode == 0x0C: # NOP pass elif opcode == 0x0D: # RLF f,d result = ((value << 1) | self.C) & 0xFF self.C = (value >> 7) & 0x01 self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x0E: # RRF f,d result = ((value >> 1) | (self.C << 7)) & 0xFF self.C = value & 0x01 self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x0F: # SUBWF f,d result = value - self.w self.C = 0 if (value < self.w) else 1 self.DC = 0 if ((value & 0x0F) < (self.w & 0x0F)) else 1 result &= 0xFF self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x10: # SWAPF f,d result = ((value >> 4) | ((value & 0x0F) << 4)) & 0xFF if d == 0: self.w = result else: self.write_ram(f, result) elif opcode == 0x11: # XORWF f,d result = self.w ^ value self.update_status(result) if d == 0: self.w = result else: self.write_ram(f, result) return True def execute_bit_instruction(self, instruction): """Führt Bit-orientierte Befehle aus""" b = (instruction >> 7) & 0x07 # Bit-Nummer f = instruction & 0x7F # File Register Address opcode = (instruction >> 10) & 0x03 value = self.read_ram(f) bit_mask = 1 << b if opcode == 0x00: # BCF f,b self.write_ram(f, value & ~bit_mask) elif opcode == 0x01: # BSF f,b self.write_ram(f, value | bit_mask) elif opcode == 0x02: # BTFSC f,b return (value & bit_mask) == 0 # Skip if bit is clear elif opcode == 0x03: # BTFSS f,b return (value & bit_mask) != 0 # Skip if bit is set return True def execute_literal_instruction(self, instruction): """Führt Literal-orientierte Befehle aus""" k = instruction & 0xFF # Literal-Wert opcode = (instruction >> 8) & 0x07 if opcode == 0x00: # ADDLW k result = self.w + k self.C = 1 if result > 0xFF else 0 self.DC = 1 if ((self.w & 0x0F) + (k & 0x0F)) > 0x0F else 0 self.w = result & 0xFF self.update_status(self.w) elif opcode == 0x01: # ANDLW k self.w = self.w & k self.update_status(self.w) elif opcode == 0x02: # IORLW k self.w = self.w | k self.update_status(self.w) elif opcode == 0x03: # MOVLW k self.w = k self.update_status(self.w) elif opcode == 0x04: # RETLW k self.w = k self.pc = self.stack[self.stack_ptr - 1] self.stack_ptr -= 1 return True elif opcode == 0x05: # SUBLW k result = k - self.w self.C = 0 if (k < self.w) else 1 self.DC = 0 if ((k & 0x0F) < (self.w & 0x0F)) else 1 self.w = result & 0xFF self.update_status(self.w) elif opcode == 0x06: # XORLW k self.w = self.w ^ k self.update_status(self.w) return True def execute_control_instruction(self, instruction): """Führt Kontrollbefehle aus""" k = instruction & 0x7FF # 11-Bit Adresse opcode = (instruction >> 11) & 0x07 if opcode == 0x00: # CALL k if self.stack_ptr < 8: self.stack[self.stack_ptr] = self.pc self.stack_ptr += 1 self.pc = k return True elif opcode == 0x01: # GOTO k self.pc = k return True elif opcode == 0x02: # RETFIE self.pc = self.stack[self.stack_ptr - 1] self.stack_ptr -= 1 # Enable interrupts return True elif opcode == 0x03: # RETURN self.pc = self.stack[self.stack_ptr - 1] self.stack_ptr -= 1 return True elif opcode == 0x04: # SLEEP self.running = False return True elif opcode == 0x05: # CLRWDT # Clear watchdog timer pass elif opcode == 0x06: # NOP pass return True def load_program(self, program): """Lädt ein Programm in den Flash-Speicher""" for i, instr in enumerate(program): if i < len(self.flash): self.flash[i] = instr & 0x3FFF def run(self, max_cycles=10000): """Führt das Programm aus""" self.running = True cycles = 0 while self.running and cycles < max_cycles: opcode = self.flash[self.pc] self.pc += 1 skip = self.execute_instruction(opcode) if skip: self.pc += 1 # Überspringe nächsten Befehl cycles += 1 self.cycle_count = cycles return cycles def dump_registers(self): """Gibt die aktuellen Registerwerte aus""" print(f"PC: 0x{self.pc:04X}") print(f"W: 0x{self.w:02X}") print(f"STATUS: 0x{self.status:02X} (C:{self.C}, DC:{self.DC}, Z:{self.Z})") print(f"PCLATH: 0x{self.pclath:02X}") print(f"INTCON: 0x{self.intcon:02X}") print(f"Cycles: {self.cycle_count}") # Beispielprogramm: Addiert zwei Zahlen und speichert das Ergebnis if __name__ == "__main__": # Beispiel-Programm (PIC-Assembler) # movlw 0x05 ; Lade 5 in W # movwf 0x0C ; Speichere W in RAM Adresse 0x0C # movlw 0x03 ; Lade 3 in W # addwf 0x0C,w ; Addiere Wert von Adresse 0x0C zu W # end program = [ 0x3005, # MOVLW 0x05 0x008C, # MOVWF 0x0C 0x3003, # MOVLW 0x03 0x070C, # ADDWF 0x0C,0 0x3FFF # NOP ] emu = PIC16F84Emulator() emu.load_program(program) print("Starte Emulator...") cycles = emu.run() print(f"\nProgramm beendet nach {cycles} Zyklen") print(f"Ergebnis im W-Register: 0x{emu.w:02X} ({emu.w})") emu.dump_registers()