mirror of
https://github.com/rzzzwilson/pymlac.git
synced 2025-06-10 09:32:41 +00:00
542 lines
18 KiB
Python
Executable File
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()
|