1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
2015-08-21 12:52:17 +07:00

542 lines
18 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
"""
GUI front-end to the IMLAC intelligent disassembler.
"""
import os
import os.path
import wx
import wx.grid
import pickle
import binimport
import disasmm
import disasmd
import disasmdata
import processmain
import processdisplay
import processdata
import mem
PROGRAMNAME = "idasm"
PROGRAMVERSION = "0.2"
objwildcard = "Papertape files (*.ptp)|*.ptp|All files (*.*)|*.*"
projwildcard = "Project files (*.idasm)|*.idasm|All files (*.*)|*.*"
grid = None
mem = None
frame = None
projectName = ""
DEFPROJSUFFIX = ".idasm"
DEFASMSUFFIX = ".asm"
DEFPTPSUFFIX = ".ptp"
def effAddr(address):
return address & 03777
def newCycleNumber():
cycle = 0
while True:
cycle += 1
yield cycle
newcycle = newCycleNumber()
def loadProject(filename):
f = open(filename, "rb")
result = pickle.Unpickler(f).load()
f.close()
return result
def saveProject(filename):
global mem, grid
f = open(filename, "wb")
p = pickle.Pickler(f, -1)
p.dump(mem)
del p
f.close()
def writeASM(filename):
global mem
if not filename.endswith('.asm'):
filename = filename + '.asm'
address = -1
lines = ""
addrlist = mem.keys()
addrlist.sort()
for addr in addrlist:
addrint = int(addr, 8)
code = mem.getCode(addrint)
opcode = mem.getOp(addrint)
field = mem.getFld(addrint)
lab = mem.getLabcount(addrint)
ref = mem.getRef(addrint)
label = ""
if lab > 0:
label = "L%05o" % effAddr(int(addr, 8))
if ref:
if field[0] == '*':
field = "*L%s" % field[1:]
else:
field = "L%s" % field
if addrint != address:
if addrint >= 0:
lines += "\t\t\t;\n"
lines += "\tORG\t%05o\t; addr code\n" % addrint
address = addrint
lines += "%s\t%s\t%s\t; %s %07o\n" % (label, opcode, field, addr, code)
address += 1
lines += "\tEND\t\t;\n"
f = open(filename, "w")
f.writelines(lines)
f.close
def fillGrid(grid, mem):
importrows = mem.len()
currentrows = grid.GetNumberRows()
if currentrows > importrows:
grid.DeleteRows(0, (currentrows - importrows))
elif importrows > currentrows:
grid.AppendRows(importrows - currentrows)
addrlist = mem.keys()
addrlist.sort()
importrows = len(addrlist)
currentrows = grid.GetNumberRows()
if currentrows > importrows:
grid.DeleteRows(0, (currentrows - importrows))
elif importrows > currentrows:
grid.AppendRows(importrows - currentrows)
i = 0
for address in addrlist:
addr = int(address, 8)
code = mem.getCode(addr)
opcode = mem.getOp(addr)
field = mem.getFld(addr)
lab = mem.getLabcount(addr)
ref = mem.getRef(addr)
label = ""
if lab > 0:
label = "L%05o" % effAddr(addr)
if ref:
if field[0] == '*':
field = "*L%s" % field[1:]
else:
field = "L%s" % field
grid.SetCellValue(i, 0, label)
grid.SetCellValue(i, 1, opcode)
grid.SetCellValue(i, 2, field)
grid.SetCellValue(i, 3, address)
grid.SetCellValue(i, 4, "%06o" % code)
i += 1
grid.ForceRefresh()
class MyPopupMenu(wx.Menu):
def __init__(self, WinName):
global grid
rows = grid.GetSelectedRows()
wx.Menu.__init__(self)
self.WinName = WinName
item = wx.MenuItem(self, wx.NewId(), "Process as MAIN instructions")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupDoMain, item)
item = wx.MenuItem(self, wx.NewId(), "Process as DISPLAY instructions")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupDoDisplay, item)
item = wx.MenuItem(self, wx.NewId(), "Process as DATA instructions")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupDoData, item)
self.AppendSeparator()
item = wx.MenuItem(self, wx.NewId(), "Set reference")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupSetRef, item)
if len(rows) > 1:
item.Enable(False)
item = wx.MenuItem(self, wx.NewId(), "Clear reference")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupClearRef, item)
if len(rows) > 1:
item.Enable(False)
self.AppendSeparator()
item = wx.MenuItem(self, wx.NewId(), "DEBUG: print types")
self.AppendItem(item)
self.Bind(wx.EVT_MENU, self.popupDoType, item)
def popupDoMain(self, event):
global grid, mem, newcycle, frame
rows = grid.GetSelectedRows()
addrlist = []
for row in rows:
addrlist.append(int(grid.GetCellValue(row, 3), 8))
thiscycle = newcycle.next()
mem.setUndo()
processmain.process(mem, addrlist, thiscycle)
fillGrid(grid, mem)
grid.ClearSelection()
frame.enableUndo(True)
def popupDoDisplay(self, event):
global grid, mem, newcycle
rows = grid.GetSelectedRows()
addrlist = []
for row in rows:
addrlist.append(int(grid.GetCellValue(row, 3), 8))
thiscycle = newcycle.next()
mem.setUndo()
processdisplay.process(mem, addrlist, thiscycle)
fillGrid(grid, mem)
grid.ClearSelection()
frame.enableUndo(True)
def popupDoData(self, event):
global grid, mem, newcycle
thiscycle = newcycle.next()
mem.setUndo()
for row in grid.GetSelectedRows():
addr = int(grid.GetCellValue(row, 3), 8)
processdata.process(mem, addr, thiscycle)
fillGrid(grid, mem)
grid.ClearSelection()
frame.enableUndo(True)
def popupSetRef(self, event):
global grid, mem
row = grid.GetSelectedRows()[0]
addrstr = grid.GetCellValue(row, 3)
addr = int(addrstr, 8)
ref = mem.getRef(addr)
memref = int(mem.getFld(addr), 8)
mem.setUndo()
if ref:
mem.decLab(memref)
mem.incLab(memref)
mem.setRef(addr)
fillGrid(grid, mem)
grid.ClearSelection()
frame.enableUndo(True)
def popupClearRef(self, event):
global grid, mem
row = grid.GetSelectedRows()[0]
addrstr = grid.GetCellValue(row, 3)
addr = int(addrstr, 8)
ref = mem.getRef(addr)
memref = int(mem.getFld(addr), 8)
if ref:
mem.setUndo()
mem.decLab(memref)
mem.clearRef(addr)
fillGrid(grid, mem)
grid.ClearSelection()
frame.enableUndo(True)
def popupDoType(self, event):
global grid, mem
for row in grid.GetSelectedRows():
addrstr = grid.GetCellValue(row, 3)
addr = int(addrstr, 8)
word = mem.getCode(addr)
cycle = mem.getCycle(addr)
type = mem.getType(addr)
lab = mem.getLabcount(addr)
ref = mem.getRef(addr)
print "row %d, addr=%s, code=%05o, cycle=%d, type=%s, lab=%s, ref=%s" % \
(row, addrstr, word, cycle, type, lab, ref)
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
global grid
# kwds["style"] = wx.MINIMIZE_BOX | wx.SYSTEM_MENU | \
# wx.CLOSE_BOX | wx.CAPTION
wx.Frame.__init__(self, *args, **kwds)
self.grid = wx.grid.Grid(self, -1, size=(353, 800))
grid = self.grid
self.__set_properties()
self.__do_layout()
self.Centre()
self.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, \
self.onGridCellRightClick, self.grid)
def __set_properties(self):
self.SetTitle(PROGRAMNAME + " " + PROGRAMVERSION)
status = self.CreateStatusBar(2, 0)
status.SetMinHeight(100)
self.SetStatusWidths([280, 70])
self.menu = self.initMenus()
self.initGrid()
def __do_layout(self):
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.grid, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
def initMenus(self):
result = wx.MenuBar()
fileMenu = wx.Menu()
fileMenu.Append(100, "Load Project", "Load disassembly project")
self.saveMenuitem = fileMenu.Append(101, "Save Project", "Save disassembly project")
self.saveAsMenuitem = fileMenu.Append(102, "Save Project As ...", \
"Save disassembly project to new file")
fileMenu.AppendSeparator()
fileMenu.Append(103, "Import Binary File", \
"Import an Imlac binary file")
self.writeASMMenuitem = fileMenu.Append(104, "Write Assembler", \
"Write an assembler source file")
fileMenu.AppendSeparator()
fileMenu.Append(199, "Exit", "Exit the program")
result.Append(fileMenu, "File")
editMenu = wx.Menu()
self.editMenu = editMenu.Append(309, "Undo", "Undo last change")
self.enableUndo(False)
result.Append(editMenu, "Edit")
helpMenu = wx.Menu()
self.helpMenu = helpMenu.Append(202, "Help", "Help on using this program")
self.helpMenu.Enable(False)
helpMenu.AppendSeparator()
helpMenu.Append(203, "About", "About this program")
result.Append(helpMenu, "Help")
self.SetMenuBar(result)
self.Bind(wx.EVT_MENU, self.Menu100, id=100)
self.Bind(wx.EVT_MENU, self.Menu101, id=101)
self.Bind(wx.EVT_MENU, self.Menu102, id=102)
self.Bind(wx.EVT_MENU, self.Menu103, id=103)
self.Bind(wx.EVT_MENU, self.Menu104, id=104)
self.Bind(wx.EVT_MENU, self.Menu199, id=199)
self.Bind(wx.EVT_MENU, self.Menu202, id=202)
self.Bind(wx.EVT_MENU, self.Menu203, id=203)
self.Bind(wx.EVT_MENU, self.Menu309, id=309)
self.enableSaveWrite(False)
return result
def enableSaveWrite(self, enable):
self.saveMenuitem.Enable(enable)
self.saveAsMenuitem.Enable(enable)
self.writeASMMenuitem.Enable(enable)
def enableUndo(self, enable):
self.editMenu.Enable(enable)
def initGrid(self):
self.grid.CreateGrid(0, 5)
self.grid.EnableGridLines(False)
self.grid.SetSelectionMode(1)
self.grid.SetDefaultRowSize(15)
self.grid.SetRowLabelSize(37)
self.grid.SetColLabelSize(20)
self.grid.SetDefaultCellAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
self.grid.SetColLabelValue(0, "Label")
self.grid.SetColSize(0, 65)
self.grid.SetColLabelValue(1, "Op")
self.grid.SetColSize(1, 65)
self.grid.SetColLabelValue(2, "Field")
self.grid.SetColSize(2, 65)
self.grid.SetColLabelValue(3, "Address")
self.grid.SetColSize(3, 65)
self.grid.SetColLabelValue(4, "Code")
self.grid.SetColSize(4, 65)
self.grid.DisableDragColSize()
self.grid.DisableDragRowSize()
self.grid.DisableDragColMove()
self.grid.EnableEditing(False)
self.grid.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_BOTTOM)
self.grid.SetRowLabelAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
self.AddrAttr = wx.grid.GridCellAttr()
self.AddrAttr.SetBackgroundColour(wx.NamedColour('papayawhip'))
self.grid.SetColAttr(3, self.AddrAttr)
self.CodeAttr = wx.grid.GridCellAttr()
self.CodeAttr.SetBackgroundColour(wx.NamedColour('lightgrey'))
self.grid.SetColAttr(4, self.CodeAttr)
self.grid.ForceRefresh()
def onGridCellRightClick(self, event):
if self.grid.GetSelectedRows():
self.PopupMenu(MyPopupMenu("test"), event.GetPosition())
else:
self.grid.ClearSelection()
event.Skip()
def Menu100(self, event):
global mem, projectName
filename = None
dlg = wx.FileDialog(self, message="Choose a project file to load",
defaultDir=os.getcwd(), defaultFile=projectName,
wildcard=projwildcard,
style=wx.OPEN | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPaths()[0]
self.grid.ClearGrid()
mem = loadProject(filename)
fillGrid(self.grid, mem)
projectName = os.path.basename(filename)
if projectName.endswith(DEFPROJSUFFIX):
projectName = projectName[:-len(DEFPROJSUFFIX)]
dlg.Destroy()
self.enableSaveWrite(True)
mem.clearUndo()
self.enableUndo(False)
def Menu101(self, event):
global mem, projectName
filename = projectName + DEFPROJSUFFIX
if projectName == "":
dlg = wx.FileDialog(self,
message="Choose a project file to save to",
defaultDir=os.getcwd(), defaultFile="",
wildcard=projwildcard,
style=wx.SAVE | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPaths()[0]
if not filename.endswith(DEFPROJSUFFIX):
filename = filename + DEFPROJSUFFIX
projectName = os.path.basename(filename)
if projectName.endswith(DEFPROJSUFFIX):
projectName = projectName[:-len(DEFPROJSUFFIX)]
dlg.Destroy()
saveProject(filename)
def Menu102(self, event):
global mem, projectName
dlg = wx.FileDialog(self,
message="Choose a project file to save as",
defaultDir=os.getcwd(), defaultFile="",
wildcard=projwildcard,
style=wx.SAVE | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPaths()[0]
saveProject(filename)
projectName = os.path.basename(filename)
if projectName.endswith(DEFPROJSUFFIX):
projectName = projectName[:-len(DEFPROJSUFFIX)]
dlg.Destroy()
def Menu103(self, event):
global mem, projectName
filename = None
dlg = wx.FileDialog(self, message="Choose an IMLAC object file to load",
defaultDir=os.getcwd(), defaultFile="",
wildcard=objwildcard,
style=wx.OPEN | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPaths()[0]
self.grid.ClearGrid()
mem = binimport.ptpimport(filename)
addrlist = mem.keys()
addrlist.sort()
importrows = len(addrlist)
currentrows = self.grid.GetNumberRows()
if currentrows > importrows:
self.grid.DeleteRows(0, (currentrows - importrows))
elif importrows > currentrows:
self.grid.AppendRows(importrows - currentrows)
i = 0
for addr in addrlist:
(code, op, fld, labcount, ref, type, cycle) = mem.getMem(int(addr, 8))
self.grid.SetCellValue(i, 1, op)
self.grid.SetCellValue(i, 2, fld)
self.grid.SetCellValue(i, 3, addr)
self.grid.SetCellValue(i, 4, "%06o" % code)
i += 1
self.grid.ForceRefresh()
projectName = os.path.basename(filename)
if projectName.endswith(DEFPTPSUFFIX):
projectName = projectName[:-len(DEFPTPSUFFIX)]
dlg.Destroy()
self.enableSaveWrite(True)
mem.clearUndo()
self.enableUndo(False)
def Menu104(self, event):
global mem, grid, projectName
filename = None
dlg = wx.FileDialog(self,
message="Choose an IMLAC assembler file to write",
defaultDir=os.getcwd(),
defaultFile=projectName + DEFASMSUFFIX,
wildcard=objwildcard,
style=wx.SAVE | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPaths()[0]
writeASM(filename)
projectName = os.path.basename(filename)
if projectName.endswith(DEFASMSUFFIX):
projectName = projectName[:-len(DEFASMSUFFIX)]
dlg.Destroy()
def Menu199(self, event):
self.Close()
def Menu202(self, event):
print "Would show help here"
def Menu203(self, event):
from wx.lib.wordwrap import wordwrap
info = wx.AboutDialogInfo()
info.Name = PROGRAMNAME
info.Version = PROGRAMVERSION
info.Copyright = "\n(C) 2007 Autotelic Systems"
info.WebSite = ("http://www.manontroppo.org", "www.manontroppo.org")
info.Description = wordwrap("\nidasm is an interactive disassembler for "
"IMLAC object files\n",
350, wx.ClientDC(self))
info.License = wordwrap("Licenced under the GPL (version 2)", 500, wx.ClientDC(self))
wx.AboutBox(info)
def Menu309(self, event):
global mem, grid
mem.undoX()
fillGrid(grid, mem)
class MyApp(wx.App):
def OnInit(self):
global frame
wx.InitAllImageHandlers()
frame = MyFrame(None, -1, "")
self.SetTopWindow(frame)
frame.Show()
return 1
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()