소스 검색

Register update

Added methods to read emulator registers from python. Also updated GUI
to update LEDs on 25FPS timer instead of events.
Min 4 년 전
부모
커밋
49962fa7e6
6개의 변경된 파일181개의 추가작업 그리고 15개의 파일을 삭제
  1. 27 0
      emulator/python/py_functions.c
  2. 15 0
      emulator/python/py_functions.h
  3. 24 0
      emulator/python/py_interface.c
  4. 2 0
      emulator/python/py_interface.h
  5. 112 14
      msp430emu/emulator.py
  6. 1 1
      readme.md

+ 27 - 0
emulator/python/py_functions.c

@@ -20,11 +20,37 @@ void pause_emu() {
 }
 }
 
 
 void reset_emu() {
 void reset_emu() {
+    if(!emuInst) return;
     emuInst->cpu->pc = 0xC000;
     emuInst->cpu->pc = 0xC000;
     print_console(emuInst, "Resetting program counter to 0xC000\n");
     print_console(emuInst, "Resetting program counter to 0xC000\n");
 }
 }
 
 
+void set_reg(uint8_t reg_type, uint8_t value) {
+    if(!emuInst) return;
+    switch(reg_type) {
+    case SET_REG_P1_IN:
+        *emuInst->cpu->p1->_IN = value;
+    }
+}
+
+PyObject *get_port1_regs() {
+    if(!emuInst) return Py_None;
+    char regs[9];
+    Port_1 *p = emuInst->cpu->p1;
+    regs[0] = *p->_OUT;
+    regs[1] = *p->_DIR;
+    regs[2] = *p->_IFG;
+    regs[3] = *p->_IES;
+    regs[4] = *p->_IE;
+    regs[5] = *p->_SEL;
+    regs[6] = *p->_SEL2;
+    regs[7] = *p->_REN;
+    regs[8] = *p->_IN;
+    return PyBytes_FromStringAndSize(regs, 9);
+}
+
 void cmd_emu(char *line, int len) {
 void cmd_emu(char *line, int len) {
+    if(!emuInst) return;
     if (!emuInst->cpu->running && emuInst->debugger->debug_mode) {
     if (!emuInst->cpu->running && emuInst->debugger->debug_mode) {
         exec_cmd(emuInst, line, len);
         exec_cmd(emuInst, line, len);
 //	         update_register_display(emu);
 //	         update_register_display(emu);
@@ -32,6 +58,7 @@ void cmd_emu(char *line, int len) {
 }
 }
 
 
 void stop_emu() {
 void stop_emu() {
+    if(!emuInst) return;
     emuInst->debugger->quit = true;
     emuInst->debugger->quit = true;
     print_console(emuInst, "Stopping emulator..\n");
     print_console(emuInst, "Stopping emulator..\n");
 }
 }

+ 15 - 0
emulator/python/py_functions.h

@@ -5,6 +5,19 @@
 
 
 #include "../emulator.h"
 #include "../emulator.h"
 #include "py_interface.h"
 #include "py_interface.h"
+#include <Python.h>
+
+
+#define SET_REG_P1_IN 0x05
+#define SET_REG_P2_IN 0x06
+
+#define GET_REG_GP 0x04
+#define GET_REG_P1 0x05
+#define GET_REG_P2 0x06
+#define GET_REG_TIMER_A 0x07
+#define GET_REG_USCI 0x08
+
+// This is an ugly solution but heh
 
 
 void play_emu();
 void play_emu();
 void pause_emu();
 void pause_emu();
@@ -12,5 +25,7 @@ void cmd_emu(char *line, int len);
 void start_emu(char *file);
 void start_emu(char *file);
 void stop_emu();
 void stop_emu();
 void reset_emu();
 void reset_emu();
+void set_reg(uint8_t reg_type, uint8_t value);
+PyObject *get_port1_regs();
 
 
 #endif
 #endif

+ 24 - 0
emulator/python/py_interface.c

@@ -26,6 +26,28 @@ static PyObject *method_cmd(PyObject *self, PyObject *args) {
     return Py_None;
     return Py_None;
 }
 }
 
 
+static PyObject *method_get_regs(PyObject *self, PyObject *args) {
+    uint8_t reg_type;
+
+    if(!PyArg_ParseTuple(args, "B", &reg_type)) {
+        return NULL;
+    }
+    switch(reg_type) {
+    case GET_REG_P1:
+        return get_port1_regs();
+    }
+    return Py_None;
+}
+
+static PyObject *method_set_regs(PyObject *self, PyObject *args) {
+    uint8_t reg_type, reg_value;
+    if(!PyArg_ParseTuple(args, "BB", &reg_type, &reg_value)) {
+        return NULL;
+    }
+    set_reg(reg_type, reg_value);
+    return Py_None;
+}
+
 static PyObject *method_stop(PyObject *self, PyObject *args) {
 static PyObject *method_stop(PyObject *self, PyObject *args) {
     stop_emu();
     stop_emu();
     Py_XDECREF(pyOnSerial);
     Py_XDECREF(pyOnSerial);
@@ -109,6 +131,8 @@ static PyMethodDef RunMethods[] = {
     {"on_serial", method_on_serial, METH_VARARGS, "Set emulator callback for serial"},
     {"on_serial", method_on_serial, METH_VARARGS, "Set emulator callback for serial"},
     {"on_console", method_on_console, METH_VARARGS, "Set emulator callback for console"},
     {"on_console", method_on_console, METH_VARARGS, "Set emulator callback for console"},
     {"on_control", method_on_control, METH_VARARGS, "Set emulator callback for control"},
     {"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"},
     {NULL, NULL, 0, NULL}
     {NULL, NULL, 0, NULL}
 };
 };
 
 

+ 2 - 0
emulator/python/py_interface.h

@@ -4,6 +4,8 @@
 #define _PY_INTERFACE_H_
 #define _PY_INTERFACE_H_
 
 
 #include "py_functions.h"
 #include "py_functions.h"
+#include "../devices/peripherals/port1.h"
+
 #include <Python.h>
 #include <Python.h>
 
 
 void print_serial (Emulator *emu, char *buf);
 void print_serial (Emulator *emu, char *buf);

+ 112 - 14
msp430emu/emulator.py

@@ -1,4 +1,4 @@
-from threading import Thread
+from threading import Thread, Event
 from os import path
 from os import path
 import _msp430emu
 import _msp430emu
 import wx
 import wx
@@ -38,7 +38,7 @@ 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 = Thread(target=self._start_emu, daemon=False)
@@ -58,6 +58,10 @@ class Emulator:
         if self.started:
         if self.started:
             _msp430emu.cmd(cmd)
             _msp430emu.cmd(cmd)
 
 
+    def get_port1_regs(self):
+        if self.started:
+            return _msp430emu.get_regs(0x05)
+
     def reset(self):
     def reset(self):
         if self.started:
         if self.started:
             _msp430emu.reset()
             _msp430emu.reset()
@@ -84,6 +88,7 @@ class Emulator:
         self.load = fname
         self.load = fname
         self.process = Thread(target=self._start_emu, daemon=False)
         self.process = Thread(target=self._start_emu, daemon=False)
         self.process.start()
         self.process.start()
+
     #     with open(self.load, 'rb') as f:
     #     with open(self.load, 'rb') as f:
     #         self.firmware = fname
     #         self.firmware = fname
     #         fdata = f.read()
     #         fdata = f.read()
@@ -153,7 +158,11 @@ class Emulator:
 
 
     def close(self):
     def close(self):
         if self.started:
         if self.started:
-            _msp430emu.stop()
+            try:
+                _msp430emu.pause()
+                _msp430emu.stop()
+            except SystemError:
+                print("Failed gradually stop emulator")
             self.process.join(2)
             self.process.join(2)
 
 
 
 
@@ -175,11 +184,15 @@ class EmulatorWindow(wx.Frame):
         menuReset = file_menu.Append(wx.ID_CLOSE_ALL, "&Reset", " Reset Emulator")
         menuReset = file_menu.Append(wx.ID_CLOSE_ALL, "&Reset", " Reset Emulator")
         self.Bind(wx.EVT_MENU, self.RestartEmulator, menuReset)
         self.Bind(wx.EVT_MENU, self.RestartEmulator, menuReset)
         menuExit = file_menu.Append(wx.ID_EXIT, "E&xit", " Terminate the program")
         menuExit = file_menu.Append(wx.ID_EXIT, "E&xit", " Terminate the program")
-        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
+        self.Bind(wx.EVT_MENU, self.OnClose, menuExit)
+        self.Bind(wx.EVT_CLOSE, self.OnExit)
 
 
         view_menu = wx.Menu()
         view_menu = wx.Menu()
-        view_console = view_menu.AppendCheckItem(101, "View Console", "Show/Hide Emulator debug console")
-        self.Bind(wx.EVT_MENU, self.ToggleConsole, view_console)
+        self.view_console = view_menu.AppendCheckItem(101, "View Console", "Show/Hide Emulator debug console")
+        self.view_registers = view_menu.AppendCheckItem(102, "View Registers", "Show/Hide Emulator registers table")
+        self.Bind(wx.EVT_MENU, self.ToggleConsole, self.view_console)
+        self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_registers)
+        self.registers = None
 
 
         menuBar = wx.MenuBar()
         menuBar = wx.MenuBar()
         menuBar.Append(file_menu, "&File")
         menuBar.Append(file_menu, "&File")
@@ -194,7 +207,8 @@ class EmulatorWindow(wx.Frame):
         self.Bind(wx.EVT_BUTTON, self.OnPause, self.btn_stop_emu)
         self.Bind(wx.EVT_BUTTON, self.OnPause, self.btn_stop_emu)
 
 
         self.btn_key = wx.Button(self, -1, "Press Key")
         self.btn_key = wx.Button(self, -1, "Press Key")
-        self.Bind(wx.EVT_BUTTON, self.OnKeyPress, self.btn_key)
+        self.btn_key.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
+        self.btn_key.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
         self.btn_rst = wx.Button(self, -1, "Reset")
         self.btn_rst = wx.Button(self, -1, "Reset")
         self.Bind(wx.EVT_BUTTON, self.OnKeyReset, self.btn_rst)
         self.Bind(wx.EVT_BUTTON, self.OnKeyReset, self.btn_rst)
 
 
@@ -253,6 +267,11 @@ class EmulatorWindow(wx.Frame):
         self.sizer.Fit(self)
         self.sizer.Fit(self)
         self.Show()
         self.Show()
 
 
+        self.timer_locked = True
+        self.timer_running = Event()
+        self.timer = Thread(target=self.OnTimer)
+        self.timer.start()
+
         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)
@@ -271,9 +290,9 @@ class EmulatorWindow(wx.Frame):
             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)
             wx.CallAfter(self.serial.AppendText, data)
-        elif event == Emulator.EVENT_GPIO:
-            self.diagram.port1[data // 2] = data % 2 == 0
-            wx.CallAfter(self.diagram.Refresh)
+        # elif event == Emulator.EVENT_GPIO:
+        #     self.diagram.port1[data // 2] = data % 2 == 0
+        #     wx.CallAfter(self.diagram.Refresh)
 
 
     def RestartEmulator(self, e):
     def RestartEmulator(self, e):
         self.emu.close()
         self.emu.close()
@@ -306,10 +325,29 @@ class EmulatorWindow(wx.Frame):
             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")
 
 
+    def OnTimer(self):
+        while 1:
+            try:
+                if self.timer_running.wait(0.04):
+                    break
+            except TimeoutError:
+                pass
+            if self.timer_locked:
+                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
+            wx.CallAfter(self.diagram.Refresh)
+            if self.view_registers.IsChecked():
+                wx.CallAfter(self.registers.set_values, self.emu)
+
     def OnPause(self, e):
     def OnPause(self, e):
         self.emu.emulation_pause()
         self.emu.emulation_pause()
         self.diagram.power = False
         self.diagram.power = False
         self.diagram.Refresh()
         self.diagram.Refresh()
+        self.emu.get_port1_regs()
+        self.timer_locked = True
 
 
     def OnStart(self, e):
     def OnStart(self, e):
         if self.load is None:
         if self.load is None:
@@ -319,13 +357,23 @@ class EmulatorWindow(wx.Frame):
             self.emu.emulation_start()
             self.emu.emulation_start()
             self.diagram.power = True
             self.diagram.power = True
             self.diagram.Refresh()
             self.diagram.Refresh()
+            self.timer_locked = False
+
+    def OnClose(self, e):
+        self.Close(True)
 
 
     def OnExit(self, e):
     def OnExit(self, e):
         self.emu.close()
         self.emu.close()
-        self.Close(True)
+        self.timer_running.set()
+        e.Skip()
 
 
-    def OnKeyPress(self, e):
-        pass
+    def OnMouseDown(self, e):
+        print("down")
+        e.Skip()
+
+    def OnMouseUp(self, e):
+        print("up")
+        e.Skip()
 
 
     def OnKeyReset(self, e):
     def OnKeyReset(self, e):
         self.diagram.port1 = [False, False, False, False, False, False, False, False]
         self.diagram.port1 = [False, False, False, False, False, False, False, False]
@@ -336,6 +384,56 @@ class EmulatorWindow(wx.Frame):
         print(text)
         print(text)
         self.serial_input.Clear()
         self.serial_input.Clear()
 
 
+    def ToggleRegisters(self, e):
+        if e.Int == 0:
+            self.registers.Close()
+        else:
+            self.registers = RegisterPanel(self)
+            self.registers.Bind(wx.EVT_CLOSE, self.OnRegistersClose)
+            self.registers.set_values(self.emu)
+
+    def OnRegistersClose(self, e):
+        self.view_registers.Check(False)
+        e.Skip()
+
+
+class RegisterPanel(wx.Frame):
+    def __init__(self, parent):
+        wx.Frame.__init__(self, parent, title="Emulator Registers")
+        self.parent = parent
+        self.grid = wx.FlexGridSizer(9, 2, 0, 10)
+        self.p1_registers = {
+            'P1OUT': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1DIR': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1IFG': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1IES': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1IE': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1SEL': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1SEL2': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1REN': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+            'P1IN': wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_NO_VSCROLL),
+        }
+        gridvals = []
+        for name, text in self.p1_registers.items():
+            text.SetMinSize((80, 15))
+            text.SetValue("00000000")
+            gridvals.append((wx.StaticText(self, label=name),))
+            gridvals.append((text, 1, wx.EXPAND))
+        self.grid.AddMany(gridvals)
+        box = wx.BoxSizer(wx.VERTICAL)
+        box.Add(self.grid, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
+        self.SetSizer(box)
+        self.Center()
+        self.Show()
+        self.Fit()
+        self.Layout()
+
+    def set_values(self, emu):
+        p1regs = emu.get_port1_regs()
+        if p1regs is not None:
+            for i, reg in enumerate(self.p1_registers.values()):
+                reg.SetValue(f"{p1regs[i]:08b}")
+
 
 
 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 """
@@ -378,4 +476,4 @@ class DrawRect(wx.Panel):
 def run(load=None):
 def run(load=None):
     app = wx.App(False)
     app = wx.App(False)
     frame = EmulatorWindow(None, "MSP430 Emulator", load)
     frame = EmulatorWindow(None, "MSP430 Emulator", load)
-    app.MainLoop()
+    app.MainLoop()

+ 1 - 1
readme.md

@@ -19,7 +19,7 @@ List of features that are added:
 
 
 - [x] Source build on linux
 - [x] Source build on linux
 - [x] Source build on windows
 - [x] Source build on windows
-- [ ] Source build on mac
+- [x] Source build on mac
 - [x] Working Emulator
 - [x] Working Emulator
 - [x] Python GUI
 - [x] Python GUI
 - [x] Blinking LEDs
 - [x] Blinking LEDs