emulator.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. from threading import Thread, Event
  2. from os import path
  3. import sys
  4. import _msp430emu
  5. import version
  6. import wx
  7. from wx.adv import RichToolTip
  8. source_dir = path.dirname(path.realpath(__file__))
  9. class Emulator:
  10. EVENT_CONSOLE = 0
  11. EVENT_SERIAL = 1
  12. EVENT_GPIO = 2
  13. P1_0_ON_PACKET = 0x00
  14. P1_0_OFF_PACKET = 0x01
  15. P1_1_ON_PACKET = 0x02
  16. P1_1_OFF_PACKET = 0x03
  17. P1_2_ON_PACKET = 0x04
  18. P1_2_OFF_PACKET = 0x05
  19. P1_3_ON_PACKET = 0x06
  20. P1_3_OFF_PACKET = 0x07
  21. P1_4_ON_PACKET = 0x08
  22. P1_4_OFF_PACKET = 0x09
  23. P1_5_ON_PACKET = 0x0A
  24. P1_5_OFF_PACKET = 0x0B
  25. P1_6_ON_PACKET = 0x0C
  26. P1_6_OFF_PACKET = 0x0D
  27. P1_7_ON_PACKET = 0x0E
  28. P1_7_OFF_PACKET = 0x0F
  29. REG_NAMES_PORT1 = ['P1OUT', 'P1DIR', 'P1IFG', 'P1IES', 'P1IE', 'P1SEL', 'P1SEL2', 'P1REN', 'P1IN']
  30. REG_NAMES_BCM = ['DCOCTL', 'BCSCTL1', 'BCSCTL2', 'BCSCTL3', 'IE1', 'IFG1']
  31. REG_NAMES_TIMER_A = [
  32. 'TA0CTL', 'TA0R', 'TA0CCTL0', 'TA0CCR0', 'TA0CCTL1', 'TA0CCR1', 'TA0CCTL2', 'TA0CCR2', 'TA0IV',
  33. 'TA1CTL', 'TA1R', 'TA1CCTL0', 'TA1CCR0', 'TA1CCTL1', 'TA1CCR1', 'TA1CCTL2', 'TA1CCR2', 'TA1IV'
  34. ]
  35. REG_NAMES_USCI = ['UCA0CTL0', 'UCA0CTL1', 'UCA0BR0', 'UCA0BR1', 'UCA0MCTL', 'UCA0STAT',
  36. 'UCA0RXBUF', 'UCA0TXBUF', 'UCA0ABCTL', 'UCA0IRTCTL', 'UCA0IRRCTL', 'IFG2'
  37. ]
  38. def __init__(self, load=None, callback=None):
  39. # self.process = Popen([path.join(emu_dir, 'MSP430'), str(ws_port)], stdout=PIPE, stderr=PIPE)
  40. # self.ws_port = ws_port
  41. # self._start_ws()
  42. self.load = load
  43. self.started = False
  44. self.callback = callback
  45. _msp430emu.on_serial(self._on_serial)
  46. _msp430emu.on_console(self._on_console)
  47. # _msp430emu.on_control(self._on_control)
  48. if self.load is not None:
  49. self.process = Thread(target=self._start_emu, daemon=False)
  50. self.process.start()
  51. def _on_serial(self, s):
  52. self._cb(self.EVENT_SERIAL, s)
  53. def _on_console(self, s):
  54. self._cb(self.EVENT_CONSOLE, s)
  55. def _on_control(self, opcode, data):
  56. if opcode <= 0x0F:
  57. self._cb(self.EVENT_GPIO, opcode)
  58. def send_command(self, cmd):
  59. if self.started:
  60. _msp430emu.cmd(cmd)
  61. def get_port1_regs(self):
  62. if self.started:
  63. return _msp430emu.get_regs(0x05)
  64. def get_bcm_regs(self):
  65. if self.started:
  66. return _msp430emu.get_regs(0x03)
  67. def get_timer_a_regs(self):
  68. if self.started:
  69. return _msp430emu.get_regs(0x07)
  70. def get_usci_regs(self):
  71. if self.started:
  72. return _msp430emu.get_regs(0x08)
  73. def set_port1_in(self, value):
  74. if 255 >= value >= 0 and self.started:
  75. return _msp430emu.set_regs(0x05, value)
  76. def reset(self):
  77. if self.started:
  78. _msp430emu.reset()
  79. def _start_emu(self):
  80. print("starting emulator...")
  81. self.started = True
  82. _msp430emu.init(self.load)
  83. print("stopping emulator...")
  84. def load_file(self, fname):
  85. self.close()
  86. print("loading " + fname)
  87. self.load = fname
  88. self.process = Thread(target=self._start_emu, daemon=False)
  89. self.process.start()
  90. def _cb(self, ev, data):
  91. if callable(self.callback):
  92. self.callback(ev, data)
  93. def __del__(self):
  94. self.close()
  95. def emulation_pause(self):
  96. if self.started:
  97. _msp430emu.pause()
  98. def emulation_start(self):
  99. if self.started:
  100. _msp430emu.play()
  101. def close(self):
  102. if self.started:
  103. try:
  104. _msp430emu.stop()
  105. except SystemError:
  106. print("Failed gradually stop emulator")
  107. self.process.join(2)
  108. class EmulatorWindow(wx.Frame):
  109. def __init__(self, parent, title, load=None):
  110. wx.Frame.__init__(self, parent, title=title)
  111. self.control = wx.TextCtrl(self, size=wx.Size(400, 450),
  112. style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
  113. self.control.Hide()
  114. self.control.WriteText("Initialising Emulator..\n")
  115. self.load = load
  116. self.emu = Emulator(load=self.load, callback=self.callback)
  117. self.serial = wx.TextCtrl(self, size=wx.Size(400, 450), style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
  118. self.serial_input = wx.TextCtrl(self)
  119. self.statusBar = self.CreateStatusBar() # A Statusbar in the bottom of the window
  120. file_menu = wx.Menu()
  121. menuFile = file_menu.Append(wx.ID_OPEN, "&Firmware", " Open firmware")
  122. self.Bind(wx.EVT_MENU, self.OnOpen, menuFile)
  123. menuReload = file_menu.Append(wx.ID_RESET, "Reload", " Reopen the same firmware file")
  124. self.Bind(wx.EVT_MENU, self.OnLoad, menuReload)
  125. # menuReset = file_menu.Append(wx.ID_CLOSE_ALL, "&Reset", " Reset Emulator")
  126. # self.Bind(wx.EVT_MENU, self.RestartEmulator, menuReset)
  127. menuAbout = file_menu.Append(wx.ID_ABOUT, "About", "About")
  128. self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
  129. menuExit = file_menu.Append(wx.ID_EXIT, "E&xit", " Terminate the program")
  130. self.Bind(wx.EVT_MENU, self.OnClose, menuExit)
  131. self.Bind(wx.EVT_CLOSE, self.OnExit)
  132. view_menu = wx.Menu()
  133. self.view_console = view_menu.AppendCheckItem(101, "View Console", "Show/Hide Emulator debug console")
  134. self.view_regs_port1 = view_menu.AppendCheckItem(102, "Port1 Registers", "Show/Hide Emulator Port1 register table")
  135. self.view_regs_bcm = view_menu.AppendCheckItem(103, "BCM Registers", "Show/Hide Emulator BCM register table")
  136. self.view_regs_timer_a = view_menu.AppendCheckItem(104, "TimerA Registers", "Show/Hide Emulator Timer A register table")
  137. self.view_regs_usci = view_menu.AppendCheckItem(105, "USCI Registers", "Show/Hide Emulator USCI register table")
  138. self.Bind(wx.EVT_MENU, self.ToggleConsole, self.view_console)
  139. self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_port1)
  140. self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_bcm)
  141. self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_timer_a)
  142. self.Bind(wx.EVT_MENU, self.ToggleRegisters, self.view_regs_usci)
  143. menuBar = wx.MenuBar()
  144. menuBar.Append(file_menu, "&File")
  145. menuBar.Append(view_menu, "&View")
  146. self.SetMenuBar(menuBar)
  147. self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
  148. self.btn_start_emu = wx.Button(self, -1, "Start")
  149. self.Bind(wx.EVT_BUTTON, self.OnStart, self.btn_start_emu)
  150. self.btn_stop_emu = wx.Button(self, -1, "Pause")
  151. self.Bind(wx.EVT_BUTTON, self.OnPause, self.btn_stop_emu)
  152. self.btn_key = wx.Button(self, -1, "Press Key")
  153. self.btn_key.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
  154. self.btn_key.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
  155. self.btn_key_down = False
  156. self.btn_rst = wx.Button(self, -1, "Reset")
  157. self.Bind(wx.EVT_BUTTON, self.OnKeyReset, self.btn_rst)
  158. self.sizer2.Add(self.btn_key, 1, wx.EXPAND)
  159. self.sizer2.Add(self.btn_start_emu, 1, wx.EXPAND)
  160. self.sizer2.Add(self.btn_stop_emu, 1, wx.EXPAND)
  161. self.sizer2.Add(self.btn_rst, 1, wx.EXPAND)
  162. self.sizer = wx.BoxSizer(wx.VERTICAL)
  163. self.sizer3 = wx.BoxSizer(wx.HORIZONTAL)
  164. self.btn_start_emu = wx.Button(self, -1, "Send")
  165. self.Bind(wx.EVT_BUTTON, self.SendSerial, self.btn_start_emu)
  166. self.sizer3.Add(self.serial_input, 1)
  167. self.sizer3.Add(self.btn_start_emu, 0)
  168. self.sizer0 = wx.BoxSizer(wx.VERTICAL)
  169. self.sizer0.Add(self.serial, 1, wx.EXPAND)
  170. self.sizer0.Add(self.sizer3, 0, wx.EXPAND)
  171. panel = wx.Panel(self, size=wx.Size(275, 375))
  172. # img =
  173. # wx.StaticBitmap(panel, -1, img, (0, 0), (img.GetWidth(), img.GetHeight()))
  174. self.diagram = DrawRect(panel, -1, size=wx.Size(275, 375))
  175. self.sizer_diagram = wx.BoxSizer(wx.VERTICAL)
  176. self.sizer_diagram.Add(panel, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)
  177. self.registers = RegisterPanel(self, self.emu)
  178. self.sizer1 = wx.BoxSizer(wx.HORIZONTAL)
  179. self.sizer1.Add(self.sizer_diagram, 0, wx.EXPAND)
  180. self.sizer1.Add(self.registers, 0, wx.EXPAND)
  181. self.sizer1.Add(self.control, 0, wx.EXPAND)
  182. self.sizer1.Add(self.sizer0, 1, wx.EXPAND)
  183. self.sizer.Add(self.sizer1, 1, wx.EXPAND)
  184. self.sizer.Add(self.sizer2, 0, wx.EXPAND)
  185. self.SetSizer(self.sizer)
  186. self.SetAutoLayout(1)
  187. self.sizer.Fit(self)
  188. self.Show()
  189. self.emu_paused = True
  190. self.timer_running = Event()
  191. self.timer = Thread(target=self.OnTimer)
  192. self.timer.start()
  193. if self.load is None:
  194. self.serial_input.Disable()
  195. self.serial.Disable()
  196. self.btn_rst.Disable()
  197. self.btn_key.Disable()
  198. self.btn_start_emu.Disable()
  199. self.btn_stop_emu.Disable()
  200. else:
  201. self.statusBar.SetStatusText("Press start to run emulation")
  202. def callback(self, event, data):
  203. if event == Emulator.EVENT_CONSOLE:
  204. wx.CallAfter(self.control.AppendText, data)
  205. elif event == Emulator.EVENT_SERIAL:
  206. wx.CallAfter(self.serial.AppendText, data)
  207. # elif event == Emulator.EVENT_GPIO:
  208. # self.diagram.port1[data // 2] = data % 2 == 0
  209. # wx.CallAfter(self.diagram.Refresh)
  210. def RestartEmulator(self, e):
  211. self.emu.close()
  212. self.control.Clear()
  213. self.serial.Clear()
  214. self.emu = Emulator(load=self.load, callback=self.callback)
  215. def ToggleConsole(self, e):
  216. if e.Int == 0:
  217. self.control.Hide()
  218. self.sizer.Fit(self)
  219. self.Layout()
  220. else:
  221. self.control.Show()
  222. self.sizer.Fit(self)
  223. self.Layout()
  224. def OnOpen(self, e):
  225. with wx.FileDialog(self, "Open Firmware File", wildcard="BIN files (*.bin)|*.bin",
  226. style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
  227. if fileDialog.ShowModal() == wx.ID_CANCEL:
  228. return
  229. self.load = fileDialog.GetPath()
  230. self.OnLoad(None)
  231. def OnLoad(self, e):
  232. if self.load is None:
  233. return
  234. self.emu.load_file(self.load)
  235. self.diagram.power = False
  236. self.emu_paused = True
  237. self.serial_input.Enable()
  238. self.serial.Enable()
  239. self.btn_rst.Enable()
  240. self.btn_key.Enable()
  241. self.btn_start_emu.Enable()
  242. self.btn_stop_emu.Enable()
  243. self.statusBar.SetStatusText("Press start to run emulation")
  244. def OnTimer(self):
  245. while 1:
  246. try:
  247. if self.timer_running.wait(0.04):
  248. break
  249. except TimeoutError:
  250. pass
  251. if self.emu_paused:
  252. continue
  253. ports = self.emu.get_port1_regs()
  254. if ports is not None:
  255. for i in range(8):
  256. self.diagram.port1[i] = (ports[0] >> i) & 1 == 1
  257. if not self.btn_key_down and ports[0] & 8 and ports[7] & 8 and not ports[1] & 8:
  258. self.emu.set_port1_in(8) # P1.3 high
  259. wx.CallAfter(self.diagram.Refresh)
  260. wx.CallAfter(self.registers.update_values)
  261. def OnPause(self, e):
  262. self.emu.emulation_pause()
  263. self.diagram.power = False
  264. self.diagram.Refresh()
  265. self.emu.get_port1_regs()
  266. self.emu_paused = True
  267. def OnStart(self, e):
  268. if self.load is None:
  269. self.OnOpen(e)
  270. else:
  271. self.statusBar.SetStatusText("")
  272. self.emu.emulation_start()
  273. self.diagram.power = True
  274. self.diagram.Refresh()
  275. self.emu_paused = False
  276. def OnClose(self, e):
  277. self.Close(True)
  278. def OnExit(self, e):
  279. self.emu.close()
  280. self.timer_running.set()
  281. e.Skip()
  282. def OnAbout(self, e):
  283. AboutWindow(self)
  284. def OnMouseDown(self, e):
  285. if self.emu_paused:
  286. e.Skip()
  287. return
  288. regs = self.emu.get_port1_regs()
  289. err = []
  290. if regs[1] & 8:
  291. err.append("P1DIR is set as output")
  292. if regs[5] & 8:
  293. err.append("P1SEL is not set to I/O function")
  294. if regs[6] & 8:
  295. err.append("P1SEL2 is not set to I/O function")
  296. if not regs[7] & 8:
  297. err.append("P1REN has pullup/pulldown resistor disabled")
  298. if regs[7] & 8 and not regs[0] & 8:
  299. err.append("P1OUT is set with pull down resistor")
  300. if len(err) > 0:
  301. tip = RichToolTip("Invalid configuration", '\n'.join(err))
  302. tip.SetIcon(wx.ICON_WARNING)
  303. tip.ShowFor(self.btn_key)
  304. else:
  305. self.btn_key_down = True
  306. self.emu.set_port1_in(0) # P1.3 low
  307. e.Skip()
  308. def OnMouseUp(self, e):
  309. if self.btn_key_down:
  310. self.emu.set_port1_in(8) # P1.3 high
  311. self.btn_key_down = False
  312. e.Skip()
  313. def OnKeyReset(self, e):
  314. self.diagram.port1 = [False, False, False, False, False, False, False, False]
  315. self.emu.reset()
  316. def SendSerial(self, e):
  317. text = self.serial_input.GetValue()
  318. print(text)
  319. self.serial_input.Clear()
  320. def ToggleRegisters(self, e):
  321. if e.Id == self.view_regs_port1.Id:
  322. panel = self.registers.panel_port1
  323. elif e.Id == self.view_regs_bcm.Id:
  324. panel = self.registers.panel_bmc
  325. elif e.Id == self.view_regs_timer_a.Id:
  326. panel = self.registers.panel_timer_a
  327. elif e.Id == self.view_regs_usci.Id:
  328. panel = self.registers.panel_usci
  329. else:
  330. return
  331. if e.Int == 0:
  332. panel.Hide()
  333. else:
  334. panel.Show()
  335. self.sizer.Fit(self)
  336. self.Layout()
  337. class RegisterPanel(wx.Panel):
  338. def __init__(self, parent, emu: Emulator):
  339. wx.Panel.__init__(self, parent)
  340. self.box = wx.BoxSizer(wx.HORIZONTAL)
  341. self.emu = emu
  342. self.regs_port1 = {name: None for name in emu.REG_NAMES_PORT1}
  343. self.regs_bcm = {name: None for name in emu.REG_NAMES_BCM}
  344. self.regs_timer_a = {name: None for name in emu.REG_NAMES_TIMER_A}
  345. self.regs_usci = {name: None for name in emu.REG_NAMES_USCI}
  346. self.grid_port1 = wx.FlexGridSizer(len(self.regs_port1), 2, 0, 10)
  347. self.grid_bmc = wx.FlexGridSizer(len(self.regs_bcm), 2, 0, 10)
  348. self.grid_timer_a = wx.FlexGridSizer(len(self.regs_timer_a), 2, 0, 10)
  349. self.grid_usci = wx.FlexGridSizer(len(self.regs_usci), 2, 0, 10)
  350. self.panel_port1 = wx.Panel(self)
  351. self.panel_bmc = wx.Panel(self)
  352. self.panel_timer_a = wx.Panel(self)
  353. self.panel_usci = wx.Panel(self)
  354. # Stucture map of [panel, grid, regs, emu func]
  355. self.__struc = [
  356. (self.panel_port1, self.grid_port1, self.regs_port1, emu.get_port1_regs),
  357. (self.panel_bmc, self.grid_bmc, self.regs_bcm, emu.get_bcm_regs),
  358. (self.panel_timer_a, self.grid_timer_a, self.regs_timer_a, emu.get_timer_a_regs),
  359. (self.panel_usci, self.grid_usci, self.regs_usci, emu.get_usci_regs),
  360. ]
  361. for panel, grid, regs, _ in self.__struc:
  362. gridvals = []
  363. for name in regs.keys():
  364. text = wx.TextCtrl(panel, style=wx.TE_READONLY | wx.TE_NO_VSCROLL)
  365. text.SetMinSize((80, 15))
  366. gridvals.append((wx.StaticText(panel, label=name),))
  367. gridvals.append((text, 1, wx.EXPAND))
  368. regs[name] = text
  369. grid.AddMany(gridvals)
  370. panel.SetSizer(grid)
  371. panel.Hide()
  372. vbox = wx.BoxSizer(wx.VERTICAL)
  373. vbox.Add(self.panel_port1, proportion=1, flag=wx.ALL | wx.EXPAND)
  374. vbox.Add(self.panel_bmc, proportion=1, flag=wx.ALL | wx.EXPAND)
  375. self.box.Add(vbox, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  376. self.box.Add(self.panel_timer_a, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  377. self.box.Add(self.panel_usci, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
  378. self.SetSizer(self.box)
  379. self.Center()
  380. self.Show()
  381. self.Fit()
  382. self.Layout()
  383. def update_values(self):
  384. for panel, _, regs, emu_func in self.__struc:
  385. if not panel.IsShown():
  386. continue
  387. values = emu_func()
  388. if values is None:
  389. continue
  390. if len(values) != len(regs):
  391. continue
  392. for i, reg in enumerate(regs.values()):
  393. reg.SetValue(f"{values[i]:08b}")
  394. class AboutWindow(wx.Frame):
  395. def __init__(self, parent, title="About"):
  396. super().__init__(parent, title=title)
  397. self.vbox = wx.BoxSizer(wx.VERTICAL)
  398. self._add_text(version.description)
  399. self._add_text("version: " + version.__version__, 20)
  400. self._add_text("wx version: " + wx.VERSION_STRING)
  401. self._add_text("python: " + sys.version)
  402. box = wx.BoxSizer()
  403. box.Add(self.vbox, 1, wx.ALL | wx.EXPAND, border=20)
  404. self.SetSizer(box)
  405. self.Layout()
  406. self.Fit()
  407. self.Center()
  408. self.Show()
  409. def _add_text(self, text, bottom=0):
  410. stext = wx.StaticText(self, label=text, style=wx.ALIGN_CENTRE_HORIZONTAL)
  411. if bottom > 0:
  412. self.vbox.Add(stext, 0, wx.BOTTOM | wx.EXPAND, border=bottom)
  413. else:
  414. self.vbox.Add(stext, 0, wx.EXPAND)
  415. class DrawRect(wx.Panel):
  416. """ class MyPanel creates a panel to draw on, inherits wx.Panel """
  417. RED = wx.Colour(255, 0, 0, wx.ALPHA_OPAQUE)
  418. GREEN = wx.Colour(0, 255, 0, wx.ALPHA_OPAQUE)
  419. def __init__(self, parent, id, **kwargs):
  420. # create a panel
  421. wx.Panel.__init__(self, parent, id, **kwargs)
  422. # self.SetBackgroundColour("white")
  423. self.Bind(wx.EVT_PAINT, self.OnPaint)
  424. self.power = False
  425. self.port1 = [False, False, False, False, False, False, False, False]
  426. self.image = wx.Bitmap(path.join(source_dir, "msp430.png"), wx.BITMAP_TYPE_PNG)
  427. def OnPaint(self, evt):
  428. """set up the device context (DC) for painting"""
  429. self.dc = wx.PaintDC(self)
  430. self.dc.DrawBitmap(self.image, 0, 0, True)
  431. if self.power:
  432. self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
  433. self.dc.SetBrush(wx.Brush(self.GREEN, wx.SOLID))
  434. # set x, y, w, h for rectangle
  435. self.dc.DrawRectangle(39, 110, 8, 15)
  436. if self.port1[6]:
  437. self.dc.SetPen(wx.Pen(self.GREEN, style=wx.TRANSPARENT))
  438. self.dc.SetBrush(wx.Brush(self.GREEN, wx.SOLID))
  439. # set x, y, w, h for rectangle
  440. self.dc.DrawRectangle(83, 356, 8, 15)
  441. if self.port1[0]:
  442. self.dc.SetPen(wx.Pen(self.RED, style=wx.TRANSPARENT))
  443. self.dc.SetBrush(wx.Brush(self.RED, wx.SOLID))
  444. self.dc.DrawRectangle(70, 356, 8, 15)
  445. del self.dc
  446. def run(load=None):
  447. app = wx.App(False)
  448. frame = EmulatorWindow(None, "MSP430 Emulator", load)
  449. app.MainLoop()