Преглед изворни кода

Interrupts and Timing

Changed timing logic, now clock cycles sectioned in epochs and each are
epochs are delayed by OS reducing cpu usage.
Added interrupt support and GPIO and simulation of unbiased circuit.
Min пре 4 година
родитељ
комит
c88a11ae10

+ 7 - 4
emulator/Makefile

@@ -8,17 +8,17 @@ all: MSP430 SERVER _msp430emu.so
 
 
 MSP430 : main.o utilities.o emu_server.o registers.o memspace.o debugger.o disassembler.o \
 MSP430 : main.o utilities.o emu_server.o registers.o memspace.o debugger.o disassembler.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o \
-	usci.o port1.o packet_queue.o bcm.o timer_a.o
-	g++ -o MSP430 launcher.o emu_server.o utilities.o registers.o memspace.o debugger.o disassembler.o \
+	usci.o port1.o packet_queue.o bcm.o timer_a.o interrupts.o
+	g++ -o MSP430 launcher.o emu_server.o utilities.o registers.o memspace.o debugger.o disassembler.o interrupts.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o usci.o port1.o bcm.o timer_a.o packet_queue.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o usci.o port1.o bcm.o timer_a.o packet_queue.o \
 	-lreadline -lwebsockets -lpthread -lrt -lssl -lcrypto;
 	-lreadline -lwebsockets -lpthread -lrt -lssl -lcrypto;
 
 
 _msp430emu.so: py_functions.o py_interface.o utilities.o registers.o memspace.o debugger.o disassembler.o \
 _msp430emu.so: py_functions.o py_interface.o utilities.o registers.o memspace.o debugger.o disassembler.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o \
-	usci.o port1.o bcm.o timer_a.o
+	usci.o port1.o bcm.o timer_a.o interrupts.o
 	$(CC) $(LLFLAGS) py_functions.o py_interface.o utilities.o registers.o memspace.o debugger.o disassembler.o \
 	$(CC) $(LLFLAGS) py_functions.o py_interface.o utilities.o registers.o memspace.o debugger.o disassembler.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o usci.o port1.o bcm.o timer_a.o \
 	register_display.o decoder.o flag_handler.o formatI.o formatII.o formatIII.o usci.o port1.o bcm.o timer_a.o \
-	-o _msp430emu.so -shared
+	interrupts.o -o _msp430emu.so -shared
 
 
 
 
 main.o : main.c
 main.o : main.c
@@ -63,6 +63,9 @@ formatII.o : devices/cpu/formatII.c
 formatIII.o : devices/cpu/formatIII.c
 formatIII.o : devices/cpu/formatIII.c
 	$(CC) $(CCFLAGS) -c devices/cpu/formatIII.c
 	$(CC) $(CCFLAGS) -c devices/cpu/formatIII.c
 
 
+interrupts.o : devices/cpu/interrupts.c
+	$(CC) $(CCFLAGS) -c devices/cpu/interrupts.c
+
 bcm.o : devices/peripherals/bcm.c
 bcm.o : devices/peripherals/bcm.c
 	$(CC) $(CCFLAGS) -c devices/peripherals/bcm.c
 	$(CC) $(CCFLAGS) -c devices/peripherals/bcm.c
 
 

+ 4 - 7
emulator/debugger/debugger.c

@@ -96,21 +96,18 @@ bool exec_cmd (Emulator *emu, char *line, int len)
   // Display disassembly of N at HEX_ADDR: dis [N] [HEX_ADDR] //
   // Display disassembly of N at HEX_ADDR: dis [N] [HEX_ADDR] //
   else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
   else if ( !strncasecmp("disas", cmd, sizeof "disas") ||
 	    !strncasecmp("dis", cmd, sizeof "dis") ||
 	    !strncasecmp("dis", cmd, sizeof "dis") ||
-	    !strncasecmp("disassemble", cmd, sizeof "disassemble")) 
-    {
+	    !strncasecmp("disassemble", cmd, sizeof "disassemble")) {
       uint16_t start_addr = cpu->pc;
       uint16_t start_addr = cpu->pc;
       uint32_t num = 10; 
       uint32_t num = 10; 
       
       
       ops = sscanf(line, "%s %u %X", bogus1, &bogus2, &bogus3);
       ops = sscanf(line, "%s %u %X", bogus1, &bogus2, &bogus3);
       
       
       if (ops == 2) {
       if (ops == 2) {
-	sscanf(line, "%s %u", bogus1, &num);
+	    sscanf(line, "%s %u", bogus1, &num);
       }
       }
       else if (ops == 3) {
       else if (ops == 3) {
-	sscanf(line, "%s %u %X", bogus1, &num, 
-		     (unsigned int *)&start_addr);
+	    sscanf(line, "%s %u %X", bogus1, &num, (unsigned int *)&start_addr);
       }
       }
-      
       disassemble(emu, start_addr, num);
       disassemble(emu, start_addr, num);
     }
     }
 
 
@@ -124,7 +121,7 @@ bool exec_cmd (Emulator *emu, char *line, int len)
       
       
       // Is it a direct address or an adress in a register being spec'd 
       // Is it a direct address or an adress in a register being spec'd 
       if (str[0] >= '0' && str[0] <= '9') {
       if (str[0] >= '0' && str[0] <= '9') {
-	sscanf(str, "%X", (unsigned int *) &start_addr);
+	    sscanf(str, "%X", (unsigned int *) &start_addr);
       }
       }
       else if (str[0] == '%' || str[0] == 'r' || str[0] == 'R')
       else if (str[0] == '%' || str[0] == 'r' || str[0] == 'R')
       {
       {

+ 20 - 6
emulator/devices/cpu/formatI.c

@@ -668,14 +668,24 @@ void decode_formatI(Emulator *emu, uint16_t instruction, bool disassemble)
        * No status bits affected
        * No status bits affected
        */
        */
       case 0xC:{
       case 0xC:{
-
         if (bw_flag == EMU_WORD) {
         if (bw_flag == EMU_WORD) {
-          *destination_addr &= (uint16_t) ~source_value;
+          // If calling __bic_SR_register_on_exit
+          if (destination_offset == 0x0023) {
+            uint16_t sr = sr_to_value(emu);
+            set_sr_value(emu, sr & ~source_value);
+          } else {
+            *destination_addr &= (uint16_t) ~source_value;
+          }
         }
         }
         else if (bw_flag == EMU_BYTE) {
         else if (bw_flag == EMU_BYTE) {
-          *(uint8_t *) destination_addr &= (uint8_t) ~source_value;	
+          // If calling __bic_SR_register_on_exit
+          if (destination_offset == 0x0023) {
+            uint16_t sr = sr_to_value(emu);
+            set_sr_value(emu, sr & (~source_value | 0xFF00));
+          } else {
+            *(uint8_t *) destination_addr &= (uint8_t) ~source_value;
+          }
         }
         }
-        
         break;
         break;
       }
       }
 
 
@@ -683,8 +693,12 @@ void decode_formatI(Emulator *emu, uint16_t instruction, bool disassemble)
        *
        *
        */
        */
       case 0xD:{
       case 0xD:{
-
-        if (bw_flag == EMU_WORD) {
+        // If calling __bis_SR_register
+        if (destination_offset == 0x0023) {
+            uint16_t sr = sr_to_value(emu);
+            set_sr_value(emu, sr | source_value);
+        }
+        else if (bw_flag == EMU_WORD) {
           *destination_addr |= (uint16_t) source_value;
           *destination_addr |= (uint16_t) source_value;
         }
         }
         else if (bw_flag == EMU_BYTE) {
         else if (bw_flag == EMU_BYTE) {

+ 8 - 4
emulator/devices/cpu/formatII.c

@@ -307,11 +307,11 @@ void decode_formatII(Emulator *emu, uint16_t instruction, bool disassemble)
       uint16_t *stack_address = get_stack_ptr(emu);
       uint16_t *stack_address = get_stack_ptr(emu);
     
     
       if (bw_flag == EMU_WORD) {
       if (bw_flag == EMU_WORD) {
-	*stack_address = source_value;
+        *stack_address = source_value;
       }
       }
       else if (bw_flag == EMU_BYTE) {
       else if (bw_flag == EMU_BYTE) {
-	*stack_address &= 0xFF00; /* Zero out bottom half for pushed byte */
-	*stack_address |= (uint8_t) source_value;
+        *stack_address &= 0xFF00; /* Zero out bottom half for pushed byte */
+        *stack_address |= (uint8_t) source_value;
       }
       }
 
 
       break;
       break;
@@ -335,7 +335,11 @@ void decode_formatII(Emulator *emu, uint16_t instruction, bool disassemble)
   
   
       //# RETI Return from interrupt: Pop SR then pop PC
       //# RETI Return from interrupt: Pop SR then pop PC
     case 0x6:{
     case 0x6:{
-       
+      set_sr_value(emu, *get_stack_ptr(emu));
+      cpu->sp += 2;
+      cpu->pc = *get_stack_ptr(emu);
+      cpu->sp += 2;
+//      printf("RETI 0x%04X 0x%04X\n", cpu->pc, sr_to_value(emu));
       break;
       break;
     }
     }
     default:{
     default:{

+ 31 - 0
emulator/devices/cpu/interrupts.c

@@ -0,0 +1,31 @@
+
+#include "interrupts.h"
+
+void service_interrupt(Emulator *emu, uint16_t cause) {
+    Cpu *cpu = emu->cpu;
+    if(!cpu->sr.GIE) return;
+    if((cpu->interrupt == NULL_VECTOR) || (cause > cpu->interrupt)) {
+        cpu->interrupt = cause;
+    }
+    return;
+}
+
+void handle_interrupts(Emulator *emu) {
+    Cpu *cpu = emu->cpu;
+    if(cpu->interrupt != NULL_VECTOR) {
+        cpu->sp -= 2;
+        uint16_t *stack_address = get_stack_ptr(emu);
+        *stack_address = cpu->pc;
+
+        cpu->sp -= 2;
+        stack_address = get_stack_ptr(emu);
+        *stack_address = sr_to_value(emu);
+        // ISV memory space (0xFFE0) + cause
+        cpu->pc = *get_addr_ptr(0xFFE0 + cpu->interrupt);
+        cpu->sr.GIE = 0;
+        cpu->sr.CPUOFF = 0;
+        cpu->sr.OSCOFF = 0;
+        cpu->sr.SCG1 = 0;
+        cpu->interrupt = NULL_VECTOR;
+    }
+}

+ 29 - 0
emulator/devices/cpu/interrupts.h

@@ -0,0 +1,29 @@
+
+
+#ifndef _INTERRUPTS_H_
+#define _INTERRUPTS_H_
+
+// From msp430g2553.h version 1.2
+#define TRAPINT_VECTOR      (0x0000)  /* 0xFFE0 TRAPINT */
+#define PORT1_VECTOR        (0x0004)  /* 0xFFE4 Port 1 */
+#define PORT2_VECTOR        (0x0006)  /* 0xFFE6 Port 2 */
+#define ADC10_VECTOR        (0x000A)  /* 0xFFEA ADC10 */
+#define USCIAB0TX_VECTOR    (0x000C)  /* 0xFFEC USCI A0/B0 Transmit */
+#define USCIAB0RX_VECTOR    (0x000E)  /* 0xFFEE USCI A0/B0 Receive */
+#define TIMER0_A1_VECTOR    (0x0010)  /* 0xFFF0 Timer0_A CC1, TA0 */
+#define TIMER0_A0_VECTOR    (0x0012)  /* 0xFFF2 Timer0_A CC0 */
+#define WDT_VECTOR          (0x0014) /* 0xFFF4 Watchdog Timer */
+#define COMPARATORA_VECTOR  (0x0016) /* 0xFFF6 Comparator A */
+#define TIMER1_A1_VECTOR    (0x0018) /* 0xFFF8 Timer1_A CC1-4, TA1 */
+#define TIMER1_A0_VECTOR    (0x001A) /* 0xFFFA Timer1_A CC0 */
+#define NMI_VECTOR          (0x001C) /* 0xFFFC Non-maskable */
+#define RESET_VECTOR        (0x001E) /* 0xFFFE Reset [Highest Priority] */
+
+#define NULL_VECTOR         (0xFFFF) /* Used by emulator indicate no interrupt */
+
+#include "../utilities.h"
+
+void service_interrupt(Emulator *emu, uint16_t cause);
+void handle_interrupts(Emulator *emu);
+
+#endif

+ 2 - 0
emulator/devices/cpu/registers.c

@@ -42,6 +42,8 @@ void initialize_msp_registers(Emulator *emu)
   cpu->r4 = cpu->r5 = cpu->r6 = cpu->r7 = cpu->r8 = 
   cpu->r4 = cpu->r5 = cpu->r6 = cpu->r7 = cpu->r8 = 
     cpu->r9 = cpu->r10 = cpu->r11 = cpu->r12 = cpu->r13 = 
     cpu->r9 = cpu->r10 = cpu->r11 = cpu->r12 = cpu->r13 = 
     cpu->r14 = cpu->r15 = 0;
     cpu->r14 = cpu->r15 = 0;
+
+  cpu->interrupt = NULL_VECTOR;
 }
 }
 
 
 void update_register_display (Emulator *emu) 
 void update_register_display (Emulator *emu) 

+ 1 - 0
emulator/devices/cpu/registers.h

@@ -127,6 +127,7 @@ typedef struct Cpu {
   Usci *usci;
   Usci *usci;
   Bcm *bcm;
   Bcm *bcm;
   Timer_a *timer_a;
   Timer_a *timer_a;
+  uint16_t interrupt;
 } Cpu;
 } Cpu;
 
 
 uint16_t sr_to_value (Emulator *emu);
 uint16_t sr_to_value (Emulator *emu);

+ 30 - 0
emulator/devices/peripherals/port1.c

@@ -296,6 +296,7 @@ void handle_port_1 (Emulator *emu)
         p->IE_3 = true;
         p->IE_3 = true;
 
 
         if (*p->_IFG & 0x08) {
         if (*p->_IFG & 0x08) {
+            if(!p->IFG_3) service_interrupt(emu, PORT1_VECTOR);
             p->IFG_3 = true;
             p->IFG_3 = true;
         }
         }
         else {
         else {
@@ -305,6 +306,9 @@ void handle_port_1 (Emulator *emu)
     else {
     else {
         p->IE_3 = false;
         p->IE_3 = false;
     }
     }
+    if (!p->DIR_3 & p->OUT_3 & p->REN_3) {
+
+    }
 
 
     ///////////////////////////////////////////////////////////////
     ///////////////////////////////////////////////////////////////
 
 
@@ -432,6 +436,30 @@ void handle_port_1 (Emulator *emu)
     else {
     else {
         p->IE_7 = false;
         p->IE_7 = false;
     }
     }
+
+    // New P1IN value
+
+    // Natural pull-up configuration
+    uint8_t value = (~*p->_DIR) & *p->_REN & *p->_OUT;
+
+    // Pins raised due to external bias
+    value |= (p->EXT_EN & p->EXT_DIR);
+
+    // Pins lowered due to external bias
+    value &= ~(p->EXT_EN & ~(p->EXT_DIR));
+
+    if(*p->_IN != value) {
+//        printf("Changing PIN 0x%02X -> 0x%02X\n", *p->_IN, value);
+        // Compute with edge trigger
+        uint8_t ifg = *p->_IE & (((~*p->_IN) & value & (~*p->_IES)) | (*p->_IN & (~value) & *p->_IES));
+        *p->_IN = value;
+        if(ifg > 0 && ifg != *p->_IFG) {
+            //printf("Interrupt %02X^%02X %02X\n", ifg, *p->_IFG, (ifg ^ *p->_IFG));
+            *p->_IFG |= ifg;
+            service_interrupt(emu, PORT1_VECTOR);
+        }
+    }
+
 }
 }
 
 
 void setup_port_1 (Emulator *emu)
 void setup_port_1 (Emulator *emu)
@@ -459,6 +487,8 @@ void setup_port_1 (Emulator *emu)
     *(p->_SEL2 = (uint8_t *) get_addr_ptr(SEL2_VLOC)) = 0;
     *(p->_SEL2 = (uint8_t *) get_addr_ptr(SEL2_VLOC)) = 0;
     *(p->_REN  = (uint8_t *) get_addr_ptr(REN_VLOC))  = 0;
     *(p->_REN  = (uint8_t *) get_addr_ptr(REN_VLOC))  = 0;
 
 
+    p->EXT_EN = 0;
+    p->EXT_DIR = 0;
   
   
     p->DIR_0 = false; p->OUT_0 = false; p->IFG_0 = false; 
     p->DIR_0 = false; p->OUT_0 = false; p->IFG_0 = false; 
     p->IE_0 = false; p->SEL_0 = false; p->SEL2_0 = false;
     p->IE_0 = false; p->SEL_0 = false; p->SEL2_0 = false;

+ 4 - 0
emulator/devices/peripherals/port1.h

@@ -36,6 +36,10 @@ struct Port_1 {
   uint8_t *_SEL2; /* r/w     PUC reset */
   uint8_t *_SEL2; /* r/w     PUC reset */
   uint8_t *_REN;  /* r/w     PUC reset */
   uint8_t *_REN;  /* r/w     PUC reset */
 
 
+  uint8_t EXT_EN; // External applied, high Z if false
+  uint8_t EXT_DIR; // External direction
+  float EXT_VOLT[8]; // External voltage
+
   // Peripherals activation flags (for emulator)
   // Peripherals activation flags (for emulator)
   bool DIR_0, OUT_0, IFG_0, IE_0, SEL_0, SEL2_0, REN_0;
   bool DIR_0, OUT_0, IFG_0, IE_0, SEL_0, SEL2_0, REN_0;
   bool DIR_1, OUT_1, IFG_1, IE_1, SEL_1, SEL2_1, REN_1;
   bool DIR_1, OUT_1, IFG_1, IE_1, SEL_1, SEL2_1, REN_1;

+ 1 - 0
emulator/devices/utilities.h

@@ -26,6 +26,7 @@
 
 
 #include "cpu/registers.h"
 #include "cpu/registers.h"
 #include "memory/memspace.h"
 #include "memory/memspace.h"
+#include "cpu/interrupts.h"
 
 
 void reg_num_to_name(uint8_t source_reg, char *reg_name);
 void reg_num_to_name(uint8_t source_reg, char *reg_name);
 int16_t *get_reg_ptr(Emulator *emu, uint8_t reg);
 int16_t *get_reg_ptr(Emulator *emu, uint8_t reg);

+ 15 - 9
emulator/python/py_functions.c

@@ -49,9 +49,14 @@ void reset_emu() {
 
 
 void set_reg(uint8_t reg_type, uint8_t value) {
 void set_reg(uint8_t reg_type, uint8_t value) {
     if(emuInst == NULL) return;
     if(emuInst == NULL) return;
+    Port_1 *p = emuInst->cpu->p1;
     switch(reg_type) {
     switch(reg_type) {
-    case SET_REG_P1_IN:
-        *emuInst->cpu->p1->_IN = value;
+    case SET_REG_P1_EN:
+    p->EXT_EN = value;
+    break;
+    case SET_REG_P1_DIR:
+    p->EXT_DIR = value;
+    break;
     }
     }
 }
 }
 
 
@@ -229,7 +234,7 @@ void start_emu(char *file) {
     setup_port_1(emuInst);
     setup_port_1(emuInst);
     setup_usci(emuInst);
     setup_usci(emuInst);
 
 
-    print_console(emuInst, " [MSP430 Emulator]\n Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)\n");
+    print_console(emuInst, "[MSP430 Emulator]\n Copyright (C) 2020 Rudolf Geosits (rgeosits@live.esu.edu)\n");
 
 
     load_bootloader(0x0C00);
     load_bootloader(0x0C00);
     if(load_firmware(emuInst, file, 0xC000) == 0) {
     if(load_firmware(emuInst, file, 0xC000) == 0) {
@@ -253,15 +258,16 @@ void start_emu(char *file) {
 
 
             // Handle Breakpoints
             // Handle Breakpoints
             //handle_breakpoints(emuInst);
             //handle_breakpoints(emuInst);
-
-            // Instruction Decoder
-            decode(emuInst, fetch(emuInst), EXECUTE);
-
-            // Handle Peripherals
-            handle_bcm(emuInst);
+            if(!cpu->sr.CPUOFF) {
+                // Instruction Decoder
+                decode(emuInst, fetch(emuInst), EXECUTE);
+                // Handle Peripherals
+                handle_bcm(emuInst);
+            }
             handle_timer_a(emuInst);
             handle_timer_a(emuInst);
             handle_port_1(emuInst);
             handle_port_1(emuInst);
             handle_usci(emuInst);
             handle_usci(emuInst);
+            handle_interrupts(emuInst);
 
 
             counter++;
             counter++;
             if(counter > 500) {
             if(counter > 500) {

+ 2 - 2
emulator/python/py_functions.h

@@ -8,8 +8,8 @@
 #include <Python.h>
 #include <Python.h>
 
 
 
 
-#define SET_REG_P1_IN 0x05
-#define SET_REG_P2_IN 0x06
+#define SET_REG_P1_EN 0x05
+#define SET_REG_P1_DIR 0x06
 
 
 #define GET_REG_BCM 0x03
 #define GET_REG_BCM 0x03
 //#define GET_REG_GP 0x04
 //#define GET_REG_GP 0x04

+ 1 - 4
msp430emu/__main__.py

@@ -5,8 +5,5 @@ import os
 if __name__ == '__main__':
 if __name__ == '__main__':
     load = None
     load = None
     if len(sys.argv) >= 2:
     if len(sys.argv) >= 2:
-        if os.path.exists(sys.argv[1]):
-            load = sys.argv[1]
-        else:
-            print(f"File '{sys.argv[1]}' does not exist")
+        load = sys.argv[1]
     emulator.run(load)
     emulator.run(load)

+ 156 - 68
msp430emu/emulator.py

@@ -1,10 +1,12 @@
-from threading import Thread, Event
+from threading import Thread, Event, RLock
+import queue
 from os import path
 from os import path
 import sys
 import sys
 import _msp430emu
 import _msp430emu
 from . import version
 from . import version
 import wx
 import wx
 from wx.adv import RichToolTip
 from wx.adv import RichToolTip
+import time
 
 
 source_dir = path.dirname(path.realpath(__file__))
 source_dir = path.dirname(path.realpath(__file__))
 
 
@@ -39,12 +41,13 @@ class Emulator:
     ]
     ]
     REG_NAMES_USCI = ['UCA0CTL0', 'UCA0CTL1', 'UCA0BR0', 'UCA0BR1', 'UCA0MCTL', 'UCA0STAT',
     REG_NAMES_USCI = ['UCA0CTL0', 'UCA0CTL1', 'UCA0BR0', 'UCA0BR1', 'UCA0MCTL', 'UCA0STAT',
                       'UCA0RXBUF', 'UCA0TXBUF', 'UCA0ABCTL', 'UCA0IRTCTL', 'UCA0IRRCTL', 'IFG2'
                       'UCA0RXBUF', 'UCA0TXBUF', 'UCA0ABCTL', 'UCA0IRTCTL', 'UCA0IRRCTL', 'IFG2'
-    ]
+                      ]
 
 
     def __init__(self, load=None, callback=None):
     def __init__(self, load=None, callback=None):
         # self.process = Popen([path.join(emu_dir, 'MSP430'), str(ws_port)], stdout=PIPE, stderr=PIPE)
         # self.process = Popen([path.join(emu_dir, 'MSP430'), str(ws_port)], stdout=PIPE, stderr=PIPE)
         # self.ws_port = ws_port
         # self.ws_port = ws_port
         # self._start_ws()
         # self._start_ws()
+
         self.load = load
         self.load = load
         self.started = False
         self.started = False
         self.callback = callback
         self.callback = callback
@@ -52,12 +55,11 @@ class Emulator:
         _msp430emu.on_serial(self._on_serial)
         _msp430emu.on_serial(self._on_serial)
         _msp430emu.on_console(self._on_console)
         _msp430emu.on_console(self._on_console)
         # _msp430emu.on_control(self._on_control)
         # _msp430emu.on_control(self._on_control)
-
         if self.load is not None:
         if self.load is not None:
-            self.process = Thread(target=self._start_emu, daemon=False)
-            self.process.start()
+            self.load_file(self.load)
 
 
     def _on_serial(self, s):
     def _on_serial(self, s):
+        print("received " + s)
         self._cb(self.EVENT_SERIAL, s)
         self._cb(self.EVENT_SERIAL, s)
 
 
     def _on_console(self, s):
     def _on_console(self, s):
@@ -71,6 +73,14 @@ class Emulator:
         if self.started:
         if self.started:
             _msp430emu.cmd(cmd)
             _msp430emu.cmd(cmd)
 
 
+    def write_serial(self, value):
+        try:
+            # self._serial_queue.put_nowait(value)
+            cmd_val = value.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t')
+            self._cb(self.EVENT_CONSOLE, f"[UART TX] {cmd_val}\n")
+        except queue.Full:
+            self._cb(self.EVENT_CONSOLE, "UART TX queue is full, this value will not be sent\n")
+
     def get_port1_regs(self):
     def get_port1_regs(self):
         if self.started:
         if self.started:
             return _msp430emu.get_regs(0x05)
             return _msp430emu.get_regs(0x05)
@@ -87,10 +97,14 @@ class Emulator:
         if self.started:
         if self.started:
             return _msp430emu.get_regs(0x08)
             return _msp430emu.get_regs(0x08)
 
 
-    def set_port1_in(self, value):
+    def set_port1_en(self, value):
         if 255 >= value >= 0 and self.started:
         if 255 >= value >= 0 and self.started:
             return _msp430emu.set_regs(0x05, value)
             return _msp430emu.set_regs(0x05, value)
 
 
+    def set_port1_dir(self, value):
+        if 255 >= value >= 0 and self.started:
+            return _msp430emu.set_regs(0x06, value)
+
     def reset(self):
     def reset(self):
         if self.started:
         if self.started:
             _msp430emu.reset()
             _msp430emu.reset()
@@ -99,14 +113,31 @@ class Emulator:
         print("starting emulator...")
         print("starting emulator...")
         self.started = True
         self.started = True
         _msp430emu.init(self.load)
         _msp430emu.init(self.load)
+        self.started = False
         print("stopping emulator...")
         print("stopping emulator...")
 
 
+    def _serial_writer(self):
+        pass
+        # while self.started:
+        #     message = self._serial_queue.get()
+        #     if message is None:
+        #         break
+        #     _msp430emu.write_serial(message)
+        #     self._serial_queue.task_done()
+        # print("stopping writer...")
+
     def load_file(self, fname):
     def load_file(self, fname):
         self.close()
         self.close()
+        if not path.exists(fname):
+            self._cb(self.EVENT_CONSOLE, f"Firmware file '{fname}' does not exist\n")
+            return
         print("loading " + fname)
         print("loading " + fname)
         self.load = fname
         self.load = fname
-        self.process = Thread(target=self._start_emu, daemon=False)
-        self.process.start()
+        # self._serial_queue = queue.Queue(maxsize=2)
+        self._process = Thread(target=self._start_emu, daemon=False)
+        # self._writer = Thread(target=self._serial_writer, daemon=False)
+        self._process.start()
+        # self._writer.start()
 
 
     def _cb(self, ev, data):
     def _cb(self, ev, data):
         if callable(self.callback):
         if callable(self.callback):
@@ -125,60 +156,79 @@ class Emulator:
 
 
     def close(self):
     def close(self):
         if self.started:
         if self.started:
+            self.started = False
             try:
             try:
                 _msp430emu.stop()
                 _msp430emu.stop()
             except SystemError:
             except SystemError:
                 print("Failed gradually stop emulator")
                 print("Failed gradually stop emulator")
-            self.process.join(2)
+            # if self._serial_queue.empty():
+            #     self._serial_queue.put_nowait(None)
+            # self._writer.join(1)
+            self._process.join(1)
 
 
 
 
 class EmulatorWindow(wx.Frame):
 class EmulatorWindow(wx.Frame):
-    def __init__(self, parent, title, load=None):
+    def __init__(self, parent, title, load=None, update_fps=25):
         wx.Frame.__init__(self, parent, title=title)
         wx.Frame.__init__(self, parent, title=title)
+        self.update_delay = 1 / update_fps
+
         self.control = wx.TextCtrl(self, size=wx.Size(400, 450),
         self.control = wx.TextCtrl(self, size=wx.Size(400, 450),
                                    style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
                                    style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
         self.control.Hide()
         self.control.Hide()
 
 
         self.control.WriteText("Initialising Emulator..\n")
         self.control.WriteText("Initialising Emulator..\n")
+
         self.load = load
         self.load = load
         self.emu = Emulator(load=self.load, callback=self.callback)
         self.emu = Emulator(load=self.load, callback=self.callback)
 
 
         self.serial = wx.TextCtrl(self, size=wx.Size(400, 450), style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
         self.serial = wx.TextCtrl(self, size=wx.Size(400, 450), style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
         self.serial_input = wx.TextCtrl(self)
         self.serial_input = wx.TextCtrl(self)
-
         self.statusBar = self.CreateStatusBar()  # A Statusbar in the bottom of the window
         self.statusBar = self.CreateStatusBar()  # A Statusbar in the bottom of the window
 
 
         file_menu = wx.Menu()
         file_menu = wx.Menu()
-        menuFile = file_menu.Append(wx.ID_OPEN, "&Firmware", " Open firmware")
-        self.Bind(wx.EVT_MENU, self.OnOpen, menuFile)
-        menuReload = file_menu.Append(wx.ID_RESET, "Reload", " Reopen the same firmware file")
-        self.Bind(wx.EVT_MENU, self.OnLoad, menuReload)
-        # menuReset = file_menu.Append(wx.ID_CLOSE_ALL, "&Reset", " Reset Emulator")
-        # self.Bind(wx.EVT_MENU, self.RestartEmulator, menuReset)
-        menuAbout = file_menu.Append(wx.ID_ABOUT, "About", "About")
-        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
-        menuExit = file_menu.Append(wx.ID_EXIT, "E&xit", " Terminate the program")
-        self.Bind(wx.EVT_MENU, self.OnClose, menuExit)
-        self.Bind(wx.EVT_CLOSE, self.OnExit)
-
         view_menu = wx.Menu()
         view_menu = wx.Menu()
-        self.view_console = view_menu.AppendCheckItem(101, "View Console", "Show/Hide Emulator debug console")
-        self.view_regs_port1 = view_menu.AppendCheckItem(102, "Port1 Registers", "Show/Hide Emulator Port1 register table")
-        self.view_regs_bcm = view_menu.AppendCheckItem(103, "BCM Registers", "Show/Hide Emulator BCM register table")
-        self.view_regs_timer_a = view_menu.AppendCheckItem(104, "TimerA Registers", "Show/Hide Emulator Timer A register table")
-        self.view_regs_usci = view_menu.AppendCheckItem(105, "USCI Registers", "Show/Hide Emulator USCI register table")
-        self.Bind(wx.EVT_MENU, self.ToggleConsole, self.view_console)
-        self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_port1)
-        self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_bcm)
-        self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_timer_a)
-        self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_usci)
+        debug_menu = wx.Menu()
+
+        self.menu_navigation = {
+            "&Firmware": (file_menu, 0, wx.ID_OPEN, "Open firmware", self.OnOpen),
+            "&Reload\tCtrl+R": (file_menu, 0, wx.ID_RESET, "Reopen the same firmware file", self.OnLoad),
+            "About": (file_menu, 0, wx.ID_ABOUT, "About", self.OnAbout),
+            "E&xit": (file_menu, 0, wx.ID_EXIT, " Terminate the program", self.OnClose),
+
+            "View Console": (view_menu, 1, wx.NewId(), "Show/Hide Emulator debug console", self.ToggleConsole),
+            "Port1 Registers": (view_menu, 1, wx.NewId(), "Show/Hide Emulator Port1 register table", self.ToggleRegisters),
+            "BCM Registers": (view_menu, 1, wx.NewId(), "Show/Hide Emulator BCM register table", self.ToggleRegisters),
+            "TimerA Registers": (view_menu, 1, wx.NewId(), "Show/Hide Emulator TimerA register table", self.ToggleRegisters),
+            "USCI Registers": (view_menu, 1, wx.NewId(), "Show/Hide Emulator USCI register table", self.ToggleRegisters),
+            "Clear serial": (view_menu, 0, wx.NewId(), "Clean text in serial window", lambda e: self.serial.Clear()),
+            "Clear console": (view_menu, 0, wx.NewId(), "Clean text in console window", lambda e: self.control.Clear()),
+
+            "Step\tCtrl+N": (debug_menu, 0, wx.NewId(), "Step single instruction", lambda e: self.emu.send_command("step")),
+            "Registers": (debug_menu, 0, wx.NewId(), "Print registers in console", lambda e: self.emu.send_command("regs")),
+        }
+
+        for name, (menu, typ, wx_id, desc, action) in self.menu_navigation.items():
+            if typ == 0:
+                button = menu.Append(wx_id, name, desc)
+            elif typ == 1:
+                button = menu.AppendCheckItem(wx_id, name, desc)
+            else:
+                continue
+            self.Bind(wx.EVT_MENU, action, button)
 
 
         menuBar = wx.MenuBar()
         menuBar = wx.MenuBar()
         menuBar.Append(file_menu, "&File")
         menuBar.Append(file_menu, "&File")
         menuBar.Append(view_menu, "&View")
         menuBar.Append(view_menu, "&View")
-
+        menuBar.Append(debug_menu, "&Debug")
         self.SetMenuBar(menuBar)
         self.SetMenuBar(menuBar)
 
 
+        accel_tbl = wx.AcceleratorTable([
+            (wx.ACCEL_CTRL, ord('R'), wx.ID_RESET),
+            (wx.ACCEL_CTRL, ord('N'), self.menu_navigation["Step\tCtrl+N"][2]),
+        ])
+        self.SetAcceleratorTable(accel_tbl)
+        self.Bind(wx.EVT_CLOSE, self.OnExit)
+
         self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
         self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
         self.btn_start_emu = wx.Button(self, -1, "Start")
         self.btn_start_emu = wx.Button(self, -1, "Start")
         self.Bind(wx.EVT_BUTTON, self.OnStart, self.btn_start_emu)
         self.Bind(wx.EVT_BUTTON, self.OnStart, self.btn_start_emu)
@@ -200,10 +250,10 @@ class EmulatorWindow(wx.Frame):
         self.sizer = wx.BoxSizer(wx.VERTICAL)
         self.sizer = wx.BoxSizer(wx.VERTICAL)
 
 
         self.sizer3 = wx.BoxSizer(wx.HORIZONTAL)
         self.sizer3 = wx.BoxSizer(wx.HORIZONTAL)
-        self.btn_start_emu = wx.Button(self, -1, "Send")
-        self.Bind(wx.EVT_BUTTON, self.SendSerial, self.btn_start_emu)
+        self.btn_send_serial = wx.Button(self, -1, "Send")
+        self.Bind(wx.EVT_BUTTON, self.SendSerial, self.btn_send_serial)
         self.sizer3.Add(self.serial_input, 1)
         self.sizer3.Add(self.serial_input, 1)
-        self.sizer3.Add(self.btn_start_emu, 0)
+        self.sizer3.Add(self.btn_send_serial, 0)
 
 
         self.sizer0 = wx.BoxSizer(wx.VERTICAL)
         self.sizer0 = wx.BoxSizer(wx.VERTICAL)
         self.sizer0.Add(self.serial, 1, wx.EXPAND)
         self.sizer0.Add(self.serial, 1, wx.EXPAND)
@@ -234,18 +284,23 @@ class EmulatorWindow(wx.Frame):
         self.Show()
         self.Show()
 
 
         self.btn_key.Disable()
         self.btn_key.Disable()
+        self.btn_send_serial.Disable()
+
         self.emu_paused = True
         self.emu_paused = True
         self.timer_running = Event()
         self.timer_running = Event()
         self.timer = Thread(target=self.OnTimer)
         self.timer = Thread(target=self.OnTimer)
         self.timer.start()
         self.timer.start()
 
 
-        if self.load is None:
+        self.serial_buffer = ""
+        self.serial_buffer_lock = RLock()
+
+        if not self.emu.started:
             self.serial_input.Disable()
             self.serial_input.Disable()
             self.serial.Disable()
             self.serial.Disable()
             self.btn_rst.Disable()
             self.btn_rst.Disable()
-            self.btn_key.Disable()
             self.btn_start_emu.Disable()
             self.btn_start_emu.Disable()
             self.btn_stop_emu.Disable()
             self.btn_stop_emu.Disable()
+            self.statusBar.SetStatusText("Open firmware file to start simulation")
         else:
         else:
             self.statusBar.SetStatusText("Press start to run emulation")
             self.statusBar.SetStatusText("Press start to run emulation")
 
 
@@ -253,7 +308,10 @@ class EmulatorWindow(wx.Frame):
         if event == Emulator.EVENT_CONSOLE:
         if event == Emulator.EVENT_CONSOLE:
             wx.CallAfter(self.control.AppendText, data)
             wx.CallAfter(self.control.AppendText, data)
         elif event == Emulator.EVENT_SERIAL:
         elif event == Emulator.EVENT_SERIAL:
-            wx.CallAfter(self.serial.AppendText, data)
+            self.serial_buffer_lock.acquire()
+            self.serial_buffer += data
+            self.serial_buffer_lock.release()
+            # wx.CallAfter(self.serial.AppendText, data)
         # elif event == Emulator.EVENT_GPIO:
         # elif event == Emulator.EVENT_GPIO:
         #     self.diagram.port1[data // 2] = data % 2 == 0
         #     self.diagram.port1[data // 2] = data % 2 == 0
         #     wx.CallAfter(self.diagram.Refresh)
         #     wx.CallAfter(self.diagram.Refresh)
@@ -286,14 +344,17 @@ class EmulatorWindow(wx.Frame):
         if self.load is None:
         if self.load is None:
             return
             return
         self.emu.load_file(self.load)
         self.emu.load_file(self.load)
-        self.diagram.power = False
+        self.diagram.reset()
         self.btn_key.Disable()
         self.btn_key.Disable()
+        self.btn_send_serial.Disable()
         self.emu_paused = True
         self.emu_paused = True
+        if not self.emu.started:
+            self.statusBar.SetStatusText("Open firmware file to start simulation")
+            return
 
 
         self.serial_input.Enable()
         self.serial_input.Enable()
         self.serial.Enable()
         self.serial.Enable()
         self.btn_rst.Enable()
         self.btn_rst.Enable()
-        self.btn_key.Enable()
         self.btn_start_emu.Enable()
         self.btn_start_emu.Enable()
         self.btn_stop_emu.Enable()
         self.btn_stop_emu.Enable()
         self.statusBar.SetStatusText("Press start to run emulation")
         self.statusBar.SetStatusText("Press start to run emulation")
@@ -301,19 +362,22 @@ class EmulatorWindow(wx.Frame):
     def OnTimer(self):
     def OnTimer(self):
         while 1:
         while 1:
             try:
             try:
-                if self.timer_running.wait(0.04):
+                if self.timer_running.wait(self.update_delay):
                     break
                     break
             except TimeoutError:
             except TimeoutError:
                 pass
                 pass
             if self.emu_paused:
             if self.emu_paused:
                 continue
                 continue
-            ports = self.emu.get_port1_regs()
-            if ports is not None:
-                for i in range(8):
-                    self.diagram.port1[i] = (ports[0] >> i) & 1 == 1
-            if not self.btn_key_down and ports[0] & 8 and ports[7] & 8 and not ports[1] & 8:
-                self.emu.set_port1_in(8)  # P1.3 high
-            wx.CallAfter(self.diagram.Refresh)
+            port1 = self.emu.get_port1_regs()
+            if port1 is not None and self.diagram.port1 != port1[0]:
+                self.diagram.port1 = port1[0]
+                wx.CallAfter(self.diagram.Refresh)
+
+            self.serial_buffer_lock.acquire()
+            if len(self.serial_buffer) > 0:
+                wx.CallAfter(self.serial.AppendText, self.serial_buffer)
+                self.serial_buffer = ""
+            self.serial_buffer_lock.release()
             wx.CallAfter(self.registers.update_values)
             wx.CallAfter(self.registers.update_values)
 
 
     def OnPause(self, e):
     def OnPause(self, e):
@@ -322,9 +386,9 @@ class EmulatorWindow(wx.Frame):
         self.diagram.Refresh()
         self.diagram.Refresh()
         self.emu.get_port1_regs()
         self.emu.get_port1_regs()
         self.btn_key.Disable()
         self.btn_key.Disable()
+        self.btn_send_serial.Disable()
         self.emu_paused = True
         self.emu_paused = True
 
 
-
     def OnStart(self, e):
     def OnStart(self, e):
         if self.load is None:
         if self.load is None:
             self.OnOpen(e)
             self.OnOpen(e)
@@ -334,6 +398,7 @@ class EmulatorWindow(wx.Frame):
             self.diagram.power = True
             self.diagram.power = True
             self.diagram.Refresh()
             self.diagram.Refresh()
             self.btn_key.Enable()
             self.btn_key.Enable()
+            self.btn_send_serial.Enable()
             self.emu_paused = False
             self.emu_paused = False
 
 
     def OnClose(self, e):
     def OnClose(self, e):
@@ -369,32 +434,32 @@ class EmulatorWindow(wx.Frame):
             tip.ShowFor(self.btn_key)
             tip.ShowFor(self.btn_key)
         else:
         else:
             self.btn_key_down = True
             self.btn_key_down = True
-            self.emu.set_port1_in(0)  # P1.3 low
+            self.emu.set_port1_en(8)  # P1.3 to ground
         e.Skip()
         e.Skip()
 
 
     def OnMouseUp(self, e):
     def OnMouseUp(self, e):
         if self.btn_key_down:
         if self.btn_key_down:
-            self.emu.set_port1_in(8)  # P1.3 high
+            self.emu.set_port1_en(0)  # P1.3 to high z
             self.btn_key_down = False
             self.btn_key_down = False
         e.Skip()
         e.Skip()
 
 
     def OnKeyReset(self, e):
     def OnKeyReset(self, e):
-        self.diagram.port1 = [False, False, False, False, False, False, False, False]
+        self.diagram.reset()
         self.emu.reset()
         self.emu.reset()
 
 
     def SendSerial(self, e):
     def SendSerial(self, e):
         text = self.serial_input.GetValue()
         text = self.serial_input.GetValue()
-        print(text)
+        self.emu.write_serial(text)
         self.serial_input.Clear()
         self.serial_input.Clear()
 
 
     def ToggleRegisters(self, e):
     def ToggleRegisters(self, e):
-        if e.Id == self.view_regs_port1.Id:
+        if e.Id == self.menu_navigation["Port1 Registers"][2]:
             panel = self.registers.panel_port1
             panel = self.registers.panel_port1
-        elif e.Id == self.view_regs_bcm.Id:
+        elif e.Id == self.menu_navigation["BCM Registers"][2]:
             panel = self.registers.panel_bmc
             panel = self.registers.panel_bmc
-        elif e.Id == self.view_regs_timer_a.Id:
+        elif e.Id == self.menu_navigation["TimerA Registers"][2]:
             panel = self.registers.panel_timer_a
             panel = self.registers.panel_timer_a
-        elif e.Id == self.view_regs_usci.Id:
+        elif e.Id == self.menu_navigation["USCI Registers"][2]:
             panel = self.registers.panel_usci
             panel = self.registers.panel_usci
         else:
         else:
             return
             return
@@ -412,7 +477,7 @@ class RegisterPanel(wx.Panel):
         self.box = wx.BoxSizer(wx.HORIZONTAL)
         self.box = wx.BoxSizer(wx.HORIZONTAL)
         self.emu = emu
         self.emu = emu
         self.regs_port1 = {name: None for name in emu.REG_NAMES_PORT1}
         self.regs_port1 = {name: None for name in emu.REG_NAMES_PORT1}
-        self.regs_bcm = {name: None for name in emu.REG_NAMES_BCM}
+        self.regs_bcm = {name: None for name in emu.REG_NAMES_BCM + ["MCLK"]}
         self.regs_timer_a = {name: None for name in emu.REG_NAMES_TIMER_A}
         self.regs_timer_a = {name: None for name in emu.REG_NAMES_TIMER_A}
         self.regs_usci = {name: None for name in emu.REG_NAMES_USCI}
         self.regs_usci = {name: None for name in emu.REG_NAMES_USCI}
 
 
@@ -457,17 +522,38 @@ class RegisterPanel(wx.Panel):
         self.Fit()
         self.Fit()
         self.Layout()
         self.Layout()
 
 
+    def _map(self, func, panel):
+        values = func()
+        if values is None:
+            return None
+        formatted = [f"{value:08b}" for value in values]
+        if panel == self.panel_bmc:
+            freq = "x"
+            if values[0] == 96 and values[1] == 135:
+                freq = "1.03"
+            elif values[0] == 0b11010001 and values[1] == 0b10000110:
+                freq = "1.00"
+            elif values[0] == 0b10010010 and values[1] == 0b10001101:
+                freq = "8.00"
+            elif values[0] == 0b10011110 and values[1] == 0b10001110:
+                freq = "12.0"
+            elif values[0] == 0b10010101 and values[1] == 0b10001111:
+                freq = "16.0"
+            formatted.append(freq + " MHz")
+        return formatted
+
     def update_values(self):
     def update_values(self):
         for panel, _, regs, emu_func in self.__struc:
         for panel, _, regs, emu_func in self.__struc:
             if not panel.IsShown():
             if not panel.IsShown():
                 continue
                 continue
-            values = emu_func()
+            values = self._map(emu_func, panel)
             if values is None:
             if values is None:
                 continue
                 continue
             if len(values) != len(regs):
             if len(values) != len(regs):
                 continue
                 continue
             for i, reg in enumerate(regs.values()):
             for i, reg in enumerate(regs.values()):
-                reg.SetValue(f"{values[i]:08b}")
+                if reg.GetValue() != values[i]:
+                    reg.SetValue(values[i])
 
 
 
 
 class AboutWindow(wx.Frame):
 class AboutWindow(wx.Frame):
@@ -494,8 +580,6 @@ class AboutWindow(wx.Frame):
             self.vbox.Add(stext, 0, wx.EXPAND)
             self.vbox.Add(stext, 0, wx.EXPAND)
 
 
 
 
-
-
 class DrawRect(wx.Panel):
 class DrawRect(wx.Panel):
     """ class MyPanel creates a panel to draw on, inherits wx.Panel """
     """ class MyPanel creates a panel to draw on, inherits wx.Panel """
     RED = wx.Colour(255, 0, 0, wx.ALPHA_OPAQUE)
     RED = wx.Colour(255, 0, 0, wx.ALPHA_OPAQUE)
@@ -507,13 +591,17 @@ class DrawRect(wx.Panel):
         # self.SetBackgroundColour("white")
         # self.SetBackgroundColour("white")
         self.Bind(wx.EVT_PAINT, self.OnPaint)
         self.Bind(wx.EVT_PAINT, self.OnPaint)
         self.power = False
         self.power = False
-        self.port1 = [False, False, False, False, False, False, False, False]
+        self.port1 = 0
         self.image = wx.Bitmap(path.join(source_dir, "msp430.png"), wx.BITMAP_TYPE_PNG)
         self.image = wx.Bitmap(path.join(source_dir, "msp430.png"), wx.BITMAP_TYPE_PNG)
 
 
+    def reset(self):
+        self.power = False
+        self.port1 = 0
+        wx.CallAfter(self.Refresh)
+
     def OnPaint(self, evt):
     def OnPaint(self, evt):
         """set up the device context (DC) for painting"""
         """set up the device context (DC) for painting"""
         self.dc = wx.PaintDC(self)
         self.dc = wx.PaintDC(self)
-
         self.dc.DrawBitmap(self.image, 0, 0, True)
         self.dc.DrawBitmap(self.image, 0, 0, True)
         if self.power:
         if self.power:
             self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
             self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
@@ -521,13 +609,13 @@ class DrawRect(wx.Panel):
             # set x, y, w, h for rectangle
             # set x, y, w, h for rectangle
             self.dc.DrawRectangle(39, 110, 8, 15)
             self.dc.DrawRectangle(39, 110, 8, 15)
 
 
-        if self.port1[6]:
+        if self.port1 & 1 << 6:
             self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
             self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
             self.dc.SetBrush(wx.Brush(self.GREEN, wx.SOLID))
             self.dc.SetBrush(wx.Brush(self.GREEN, wx.SOLID))
             # set x, y, w, h for rectangle
             # set x, y, w, h for rectangle
             self.dc.DrawRectangle(83, 356, 8, 15)
             self.dc.DrawRectangle(83, 356, 8, 15)
 
 
-        if self.port1[0]:
+        if self.port1 & 1:
             self.dc.SetPen(wx.Pen(self.RED, style=wx.TRANSPARENT))
             self.dc.SetPen(wx.Pen(self.RED, style=wx.TRANSPARENT))
             self.dc.SetBrush(wx.Brush(self.RED, wx.SOLID))
             self.dc.SetBrush(wx.Brush(self.RED, wx.SOLID))
             self.dc.DrawRectangle(70, 356, 8, 15)
             self.dc.DrawRectangle(70, 356, 8, 15)

+ 5 - 0
readme.md

@@ -27,6 +27,11 @@ List of features that are added:
 - [ ] UART Serial input
 - [ ] UART Serial input
 - [x] Reset button
 - [x] Reset button
 - [x] Button for P1.3
 - [x] Button for P1.3
+- [x] Interrupts
+- [ ] Timer A
+- [ ] PWM Signals
+- [x] Unbiased circuit simulation (due to internal pull-up/down resistors)
+- [ ] Watchdog Timer
 - [ ] GPIO Oscilloscope
 - [ ] GPIO Oscilloscope
 - [ ] Port 2 GPIO
 - [ ] Port 2 GPIO
 - [ ] Invalid register configuration checks
 - [ ] Invalid register configuration checks

+ 1 - 0
setup.py

@@ -14,6 +14,7 @@ emulator_files = [
     'emulator/devices/cpu/formatI.c',
     'emulator/devices/cpu/formatI.c',
     'emulator/devices/cpu/formatII.c',
     'emulator/devices/cpu/formatII.c',
     'emulator/devices/cpu/formatIII.c',
     'emulator/devices/cpu/formatIII.c',
+    'emulator/devices/cpu/interrupts.c',
     'emulator/devices/peripherals/bcm.c',
     'emulator/devices/peripherals/bcm.c',
     'emulator/devices/peripherals/timer_a.c',
     'emulator/devices/peripherals/timer_a.c',
     'emulator/devices/peripherals/usci.c',
     'emulator/devices/peripherals/usci.c',