Sfoglia il codice sorgente

Working UART interrupts

Min 4 anni fa
parent
commit
b30a06b73b

+ 7 - 0
emulator/devices/cpu/formatI.c

@@ -415,6 +415,13 @@ void decode_formatI(Emulator *emu, uint16_t instruction, bool disassemble)
   
 
   if (!disassemble) {
+
+    // USCI reset interrupt flag when UCA0RXBUF is read
+    if(as_flag == 1 && source == 2) {
+      // FIXME: might not catch all cases
+      if(source_offset == 0x0066) *cpu->usci->IFG2 &= ~RXIFG;
+    }
+
     switch (opcode) {
       
       /* MOV SOURCE, DESTINATION

+ 5 - 24
emulator/devices/cpu/registers.c

@@ -21,29 +21,8 @@
 //##########+++ MSP430 Register initialization +++##########
 void initialize_msp_registers(Emulator *emu)
 {
-  Cpu *cpu = emu->cpu;
-  Debugger *debugger = emu->debugger;
-
-  /* Initialize PC to boot loader code on cold boot (COLD)*/
-  //cpu->pc = 0x0C00;
-
-  /* Initialize Program Counter to *0xFFFE at boot or reset (WARM)*/
-  cpu->pc = 0xC000;
-  
-  /* Stack pointer typically begins at the top of RAM after reset */
-  cpu->sp = 0x400;
-
-  /* Initialize the status register */
-  memset(&cpu->sr, 0, sizeof(Status_reg));
-
-  cpu->running = false;
-  cpu->cg2 = 0;
-
-  cpu->r4 = cpu->r5 = cpu->r6 = cpu->r7 = cpu->r8 = 
-    cpu->r9 = cpu->r10 = cpu->r11 = cpu->r12 = cpu->r13 = 
-    cpu->r14 = cpu->r15 = 0;
-
-  cpu->interrupt = NULL_VECTOR;
+  cpu_reset(emu);
+  emu->cpu->running = false;
 }
 
 void update_register_display (Emulator *emu) 
@@ -214,12 +193,14 @@ void cpu_step(Emulator *emu) {
     handle_port_1(emu);
     handle_usci(emu);
     handle_interrupts(emu);
-
+    cpu->nsecs += cpu->bcm->mclk_period;
 }
 void cpu_reset(Emulator *emu) {
     Cpu *cpu = emu->cpu;
     cpu->pc = 0xC000;
     cpu->sp = 0x400;
+    cpu->nsecs = 0;
+
     memset(&cpu->sr, 0, sizeof(Status_reg));
     cpu->cg2 = cpu->r4  = cpu->r5  = cpu->r6  = cpu->r7 =
     cpu->r8  =  cpu->r9 = cpu->r10 = cpu->r11 = cpu->r12 =

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

@@ -128,6 +128,7 @@ typedef struct Cpu {
   Bcm *bcm;
   Timer_a *timer_a;
   uint16_t interrupt;
+  uint64_t nsecs;  // nanoseconds since emulator started;
 } Cpu;
 
 uint16_t sr_to_value (Emulator *emu);

+ 8 - 7
emulator/devices/peripherals/bcm.c

@@ -36,12 +36,17 @@ void handle_bcm (Emulator *emu)
   if (SELMx == 0b00 || SELMx == 0b01) { // source = DCOCLK
     bcm->mclk_source = DCOCLK;
     bcm->mclk_freq = (bcm->dco_freq*1.0) / bcm->mclk_div;
+    bcm->mclk_period = (1.0/(bcm->mclk_freq))*1000000000.0;
   }
   else if (SELMx == 0b10) { // XT2CLK
-    bcm->mclk_source = XT2CLK;    
+    bcm->mclk_source = XT2CLK;
+    bcm->mclk_freq = 0;
+    bcm->mclk_period = 0;
   }
   else if (SELMx == 0b11) { // VLOCLK
-    bcm->mclk_source = VLOCLK;    
+    bcm->mclk_source = VLOCLK;
+    bcm->mclk_freq = 12000 / bcm->mclk_div;
+    bcm->mclk_period = (1.0/(bcm->mclk_freq))*1000000000.0;
   }
 
   switch (DIVMx) {
@@ -174,11 +179,7 @@ double mclk_clock_nstime(Emulator *emu) {
     Bcm *bcm = cpu->bcm;
     double nsec;
 
-    if (bcm->mclk_source == DCOCLK) {
-        nsec = (1.0/(bcm->dco_freq/bcm->mclk_div))*1000000000.0;
-    } else {
-        nsec = (1.0/1030000) * 1000000000.0;
-    }
+    nsec = (1.0/(bcm->mclk_freq))*1000000000.0;
     return nsec;
 }
 

+ 1 - 0
emulator/devices/peripherals/bcm.h

@@ -57,6 +57,7 @@ struct Bcm {
   uint8_t mclk_source;
   uint64_t mclk_div;
   uint64_t mclk_freq;
+  uint64_t mclk_period; // in manosecs
 };
 
 //uint64_t nanosec_diff(struct timespec *timeA_p, struct timespec *timeB_p);

+ 87 - 31
emulator/devices/peripherals/usci.c

@@ -98,43 +98,90 @@ void open_pty (Emulator *emu)
 }
 */
 
+const uint32_t VALID_BAUD[] = {
+    1200, 2400, 4800, 9600, 19200, 38400, 56000, 115200, 128000, 256000
+};
+
+void set_uart_buf(Emulator *emu, uint8_t *buf, int len) {
+  Usci *usci = emu->cpu->usci;
+  free(usci->UART_buf_data);
+  usci->UART_buf_data = malloc(len);
+  memcpy(usci->UART_buf_data, buf, len);
+  usci->UART_buf_pnt = 0;
+  usci->UART_buf_len = len;
+}
+
 void handle_usci (Emulator *emu) {
   Cpu *cpu = emu->cpu;
   Debugger *deb = emu->debugger;
   Usci *usci = cpu->usci;
   Port_1 *p1 = cpu->p1;
-  
-  static bool uart_active = false;
-  
-  // Handle sending from TX pin (P1.2) 
-  if (p1->SEL_2 && p1->SEL2_2) {
-    if (uart_active == false) {
-      puts("UART TX pin activated on P1.2");
-      uart_active = true;
-    }
 
-    // UCAxTXIFG
-    if (*usci->IFG2 & TXIFG) {
-      uint8_t c = *usci->UCA0TXBUF;
-      unsigned char str[2];
-      str[0] = c;
-      str[1] = 0;
-
-      *usci->IFG2 &= ~TXIFG;
-
-      if (c & 0xFF) {
-        if (deb->web_interface) {
-            print_serial(emu, (char*)&str[0]);
-            //write(sp, usci->UCA0TXBUF, 1);
+  if (!usci->USCI_RESET && (*usci->UCA0CTL1 & 0x01)) {
+    usci->USCI_RESET = true;
+  }
+  else if (usci->USCI_RESET && !(*usci->UCA0CTL1 & 0x01)) {
+    uint64_t clock = 0;
+    usci->UART_baud = 0;
+    usci->USCI_RESET = false;
+    if((*usci->UCA0CTL1 & 0xc0) == 0x40) { // USCI clock source is ACLK
+        clock = 32768;
+    } else if ((*usci->UCA0CTL1 & 0x80) == 0x80) { // SMCLK
+        clock = cpu->bcm->mclk_freq;
+    }
+    if(clock > 0) {
+        double baud = clock / *usci->UCA0BR0;
+        for(int i=0;i < sizeof(VALID_BAUD); i++) {
+            double diff = ((double)VALID_BAUD[i])/baud;
+            if(diff < 1.1 && diff > 0.9) {  // If error less than +/- 10%
+                usci->UART_baud = VALID_BAUD[i];
+                char message[35] = {0};
+                sprintf(message, "Detected UART Baud Rate: %d\n", usci->UART_baud);
+                print_console(emu, message);
+                break;
+            }
+        }
+    }
+    if(usci->UART_baud == 0) {
+        print_console(emu, "Invalid UART Baud Rate\n");
+    }
+  }
+  if(usci->UART_baud > 0) {
+
+    // Handle signal from RX pin (P1.1)
+    if (p1->SEL_1 && p1->SEL2_1) {
+      if((usci->UART_buf_pnt < usci->UART_buf_len) && !(*usci->IFG2 & RXIFG)) {
+        uint64_t symbol_period = 1000000000/usci->UART_baud;
+        if(cpu->nsecs >= (usci->UART_buf_sent + symbol_period)) {
+          *usci->UCA0RXBUF = usci->UART_buf_data[usci->UART_buf_pnt];
+          *usci->IFG2 |= RXIFG;
+          usci->UART_buf_pnt++;
+          usci->UART_buf_sent = cpu->nsecs; // Last time symbol was sent;
+          if(*usci->IE2 & UCA0RXIE) {
+            service_interrupt(emu, USCIAB0RX_VECTOR);
+          }
         }
-        //else if (deb->console_interface) {
-            //write(sp, usci->UCA0TXBUF, 1);
-        //}
-	    *usci->UCA0TXBUF = 0;
       }
-
-      //*usci->IFG2 &= TXIFG;
-      *usci->IFG2 |= TXIFG;
+    }
+    // Handle sending from TX pin (P1.2)
+    if (p1->SEL_2 && p1->SEL2_2) {
+      // UCAxTXIFG
+      if (*usci->IFG2 & TXIFG) {
+        uint8_t c = *usci->UCA0TXBUF;
+        unsigned char str[2];
+        str[0] = c;
+        str[1] = 0;
+
+        *usci->IFG2 &= ~TXIFG;
+
+        if (c & 0xFF) {
+          if (deb->web_interface) {
+              print_serial(emu, (char*)&str[0]);
+          }
+  	    *usci->UCA0TXBUF = 0;
+        }
+        *usci->IFG2 |= TXIFG;
+      }
     }
   }
   return;
@@ -156,8 +203,9 @@ void setup_usci (Emulator *emu)
   static const uint16_t UCA0ABCTL_VLOC = 0x5D; // Auto-Baud control register
   static const uint16_t UCA0IRTCTL_VLOC = 0x5E; // IrDA transmit control reg
   static const uint16_t UCA0IRRCTL_VLOC = 0x5F; // IrDA Receive control reg
-  static const uint16_t IFG2_VLOC       = 0x03; // Interrupt flag register 2
-  
+  static const uint16_t IE2_VLOC        = 0x01; // SFR interrupt enable register 2
+  static const uint16_t IFG2_VLOC       = 0x03; // SFR interrupt flag register 2
+
   // Set initial values
   *(usci->UCA0CTL0   = (uint8_t *) get_addr_ptr(UCA0CTL0_VLOC))  = 0;
   *(usci->UCA0CTL1  = (uint8_t *) get_addr_ptr(UCA0CTL1_VLOC))   = 0x01;
@@ -171,7 +219,15 @@ void setup_usci (Emulator *emu)
   *(usci->UCA0IRTCTL  = (uint8_t *) get_addr_ptr(UCA0IRTCTL_VLOC)) = 0;
   *(usci->UCA0IRRCTL  = (uint8_t *) get_addr_ptr(UCA0IRRCTL_VLOC)) = 0;  
 
+  usci->IE2  = (uint8_t *) get_addr_ptr(IE2_VLOC);
   usci->IFG2  = (uint8_t *) get_addr_ptr(IFG2_VLOC);
   *usci->IFG2 |= TXIFG;
   *usci->IFG2 &= ~RXIFG;
+
+  usci->UART_buf_data = NULL;
+  usci->UART_buf_len = 0;
+  usci->UART_buf_pnt = 0;
+  usci->UART_buf_sent = 0;
+  usci->UART_baud = 0;
+  usci->USCI_RESET = false;
 }

+ 13 - 1
emulator/devices/peripherals/usci.h

@@ -29,6 +29,9 @@
 #define TXIFG 0x02
 #define RXIFG 0x01
 
+#define UCA0TXIE 0x02
+#define UCA0RXIE 0x01
+
 // USCI_Ax Control Register 0
 typedef struct Ctl0 
 {
@@ -90,12 +93,21 @@ typedef struct Usci
   uint8_t *UCA0IRTCTL;
   uint8_t *UCA0IRRCTL;
 
+  uint8_t *IE2;
   uint8_t *IFG2;
-  
+
   Ctl0 ctl0;
   Ctl1 ctl1;
+
+  uint8_t *UART_buf_data;
+  int UART_buf_len;
+  int UART_buf_pnt;
+  uint64_t UART_buf_sent;
+  uint32_t UART_baud;
+  bool USCI_RESET;
 }
 Usci;
 
 void setup_usci(Emulator *emu);
 void handle_usci(Emulator *emu);
+void set_uart_buf(Emulator *emu, uint8_t *buf, int len);

+ 58 - 33
emulator/python/py_functions.c

@@ -60,6 +60,28 @@ void set_reg(uint8_t reg_type, uint8_t value) {
     }
 }
 
+PyObject *get_misc_data() {
+    if(emuInst == NULL) return Py_None;
+    Cpu *cpu = emuInst->cpu;
+    Bcm *bcm = cpu->bcm;
+    PyObject *dict = PyDict_New();
+    PyDict_SetItemString(dict, "period", PyLong_FromUnsignedLongLong(cpu->nsecs));
+    PyDict_SetItemString(dict, "mclk", PyLong_FromUnsignedLongLong(bcm->mclk_freq));
+
+    PyObject *mck_src_str;
+    switch(bcm->mclk_source) {
+        case DCOCLK: {mck_src_str = PyUnicode_FromString("DCOCLK"); break;}
+        case XT2CLK: {mck_src_str = PyUnicode_FromString("XT2CLK"); break;}
+        case VLOCLK: {mck_src_str = PyUnicode_FromString("VLOCLK"); break;}
+        default: {mck_src_str = PyUnicode_FromString("?"); break;}
+//         TACLK, ACLK, SMCLK, MCLK, INCLK, NUM_CLOCKS
+    }
+    PyDict_SetItemString(dict, "mclk_src", mck_src_str);
+    PyDict_SetItemString(dict, "uart_baud", PyLong_FromUnsignedLong(cpu->usci->UART_baud));
+
+    return dict;
+}
+
 PyObject *get_port1_regs() {
     if(emuInst == NULL) return Py_None;
     char regs[9];
@@ -166,35 +188,38 @@ void stop_emu() {
 
 void write_serial(uint8_t *data, int len) {
     if(emuInst == NULL) return;
-    Usci *usci = emuInst->cpu->usci;
-//    int i = 0;
-//    uint8_t *bytes = data;
-
-    printf("len is %d\n", len);
-    for(int i=0; i < len; i++) {
-        usleep(333);
-        printf("waiting.. ");
-        while (*usci->IFG2 & RXIFG) {
-            usleep(333);
-            if(emuInst->debugger->quit) {
-                puts("debugger stopped");
-                return;
-            }
-        }
-//        uint8_t thing = *(bytes);
-        *usci->UCA0RXBUF = data[i];
-        *usci->IFG2 |= RXIFG;
-        printf("0x%04X in UCA0RXBUF\n", (uint8_t)*usci->UCA0RXBUF);
-        printf("waiting.. ");
-        while (*usci->IFG2 & RXIFG) {
-            usleep(333);
-            if(emuInst->debugger->quit) {
-                puts("debugger stopped");
-                return;
-            }
-        }
-        puts("done\n");
-    }
+    set_uart_buf(emuInst, data, len);
+////    int i = 0;
+////    uint8_t *bytes = data;
+//    *usci->UCA0RXBUF = data[0];
+//    *usci->IFG2 |= RXIFG;
+//    puts("Setting interrupt");
+//    service_interrupt(emuInst, USCIAB0RX_VECTOR);
+//    printf("len is %d\n", len);
+//    for(int i=0; i < len; i++) {
+//        usleep(333);
+//        printf("waiting.. ");
+//        while (*usci->IFG2 & RXIFG) {
+//            usleep(333);
+//            if(emuInst->debugger->quit) {
+//                puts("debugger stopped");
+//                return;
+//            }
+//        }
+////        uint8_t thing = *(bytes);
+//        *usci->UCA0RXBUF = data[i];
+//        *usci->IFG2 |= RXIFG;
+//        printf("0x%04X in UCA0RXBUF\n", (uint8_t)*usci->UCA0RXBUF);
+//        printf("waiting.. ");
+//        while (*usci->IFG2 & RXIFG) {
+//            usleep(333);
+//            if(emuInst->debugger->quit) {
+//                puts("debugger stopped");
+//                return;
+//            }
+//        }
+//        puts("done\n");
+//    }
 
 
 //    while (true) {
@@ -216,8 +241,6 @@ void write_serial(uint8_t *data, int len) {
 //        if (*usci->UCA0RXBUF == '\r' || *usci->UCA0RXBUF == '\n') break;
 //        ++bytes;
 //      }
-//      return NULL;
-//    }
 }
 
 void start_emu(char *file) {
@@ -275,9 +298,10 @@ void start_emu(char *file) {
             counter++;
             if(counter > 500) {
                 uint64_t time_now = getnano();
+                if(cpu->bcm->mclk_period == 0) break;
 
-                // Average of 4 cycles per instruction (actually around 4.88)
-                uint64_t cycles_time = (uint64_t)(mclk_clock_nstime(emuInst) * 4.883 * 500);
+                // Average of 4 cycles per instruction
+                uint64_t cycles_time = (uint64_t)(cpu->bcm->mclk_period * 4.883 * 500);
                 uint64_t delta = time_now - time_last;
                 if(time_last > time_now) delta = 0;
                 uint64_t sleep_time = cycles_time - delta;
@@ -297,6 +321,7 @@ void start_emu(char *file) {
     }
 
     uninitialize_msp_memspace();
+    free(cpu->usci->UART_buf_data);
     free(cpu->timer_a);
     free(cpu->bcm);
     free(cpu->p1);

+ 1 - 0
emulator/python/py_functions.h

@@ -32,6 +32,7 @@ PyObject *get_port1_regs();
 PyObject *get_bcm_regs();
 PyObject *get_timer_regs();
 PyObject *get_usci_regs();
+PyObject *get_misc_data();
 void write_serial(uint8_t *data, int len);
 
 #endif

+ 5 - 0
emulator/python/py_interface.c

@@ -140,6 +140,10 @@ static PyObject *method_write_serial(PyObject *self, PyObject *args) {
     return Py_None;
 }
 
+static PyObject *method_set_misc(PyObject *self, PyObject *args) {
+    return get_misc_data();
+}
+
 
 static PyMethodDef RunMethods[] = {
     {"init", method_start, METH_VARARGS, "Initialise msp430 emulator"},
@@ -153,6 +157,7 @@ static PyMethodDef RunMethods[] = {
     {"on_control", method_on_control, METH_VARARGS, "Set emulator callback for control"},
     {"get_regs", method_get_regs, METH_VARARGS, "Get emulator registers"},
     {"set_regs", method_set_regs, METH_VARARGS, "Set emulator registers"},
+    {"get_misc", method_set_misc, METH_NOARGS, "Get emulator miscellaneous information"},
     {"write_serial", method_write_serial, METH_VARARGS, "Write to UART serial"},
     {NULL, NULL, 0, NULL}
 };

+ 12 - 24
msp430emu/emulator.py

@@ -7,6 +7,7 @@ from . import version
 import wx
 from wx.adv import RichToolTip
 import time
+import re
 
 source_dir = path.dirname(path.realpath(__file__))
 
@@ -46,7 +47,6 @@ class Emulator:
             self.load_file(self.load)
 
     def _on_serial(self, s):
-        print("received " + s)
         self._cb(self.EVENT_SERIAL, s)
 
     def _on_console(self, s):
@@ -60,13 +60,16 @@ class Emulator:
         if self.started:
             _msp430emu.cmd(cmd)
 
+    def get_misc_info(self):
+        if self.started:
+            return _msp430emu.get_misc()
+
     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")
+        formatted = value.replace('\\n', '\n').replace('\\r', '\r').replace('\\t', '\t')
+        for match in re.findall(r'(\\x[0-9a-f]{1,2})', formatted, re.IGNORECASE):
+            formatted = formatted.replace(match, chr(int(match[-2:], 16)))
+        _msp430emu.write_serial(formatted)
+        self._cb(self.EVENT_CONSOLE, f"[UART TX] {value}\n")
 
     def get_port1_regs(self):
         if self.started:
@@ -107,16 +110,6 @@ class Emulator:
         self.started = False
         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):
         self.close()
         if not path.exists(fname):
@@ -124,11 +117,8 @@ class Emulator:
             return
         print("loading " + fname)
         self.load = fname
-        # 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):
         if callable(self.callback):
@@ -152,9 +142,6 @@ class Emulator:
                 _msp430emu.stop()
             except SystemError:
                 print("Failed gradually stop emulator")
-            # if self._serial_queue.empty():
-            #     self._serial_queue.put_nowait(None)
-            # self._writer.join(1)
             self._process.join(1)
 
 
@@ -197,6 +184,7 @@ class EmulatorWindow(wx.Frame):
 
             "Step\tCtrl+N": (debug_menu, 0, wx.NewId(), "Step single instruction", self.OnStep),
             "Registers": (debug_menu, 0, wx.NewId(), "Print registers in console", lambda e: self.emu.send_command("regs")),
+            "Misc": (debug_menu, 0, wx.NewId(), "", lambda e: print(self.emu.get_misc_info())),
         }
 
         for name, (menu, typ, wx_id, desc, action) in self.menu_navigation.items():
@@ -378,7 +366,7 @@ class EmulatorWindow(wx.Frame):
         self.diagram.Refresh()
         self.emu.get_port1_regs()
         self.btn_key.Disable()
-        self.btn_send_serial.Disable()
+        # self.btn_send_serial.Disable()
         self.emu_paused = True
 
     def OnStart(self, e):

+ 2 - 2
readme.md

@@ -24,7 +24,7 @@ List of features that are added:
 - [x] Python GUI
 - [x] Blinking LEDs
 - [x] UART Serial output
-- [ ] UART Serial input
+- [x] UART Serial input
 - [x] Reset button
 - [x] Button for P1.3
 - [x] Interrupts
@@ -35,5 +35,5 @@ List of features that are added:
 - [ ] GPIO Oscilloscope
 - [ ] Port 2 GPIO
 - [ ] Invalid register configuration checks
-- [ ] Information about UART Band
+- [x] Information about UART Band
 - [ ] ADC