1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
2016-02-06 10:49:18 +07:00

570 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.3"
objwildcard = "Papertape files (*.ptp)|*.ptp|All files (*.*)|*.*"
projwildcard = "Project files (*.idasm)|*.idasm|All files (*.*)|*.*"
grid = None
mem = None
frame = None
projectName = ""
(ColumnCode, ColumnAddress, ColumnLabel, ColumnOpcode, ColumnField) = range(5)
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()
# get number of 'gaps' in the memory map
num_gaps = 0
gap_addr = [] # list of addresses after which there is a gap
last_addr = None
for addr in addrlist:
addr = int(addr, 8)
if last_addr is not None and addr != last_addr + 1:
num_gaps += 1
gap_addr.append(last_addr)
last_addr = addr
# figure out changes in number of rows
new_rows = importrows + num_gaps
if currentrows > new_rows:
grid.DeleteRows(0, (currentrows - new_rows))
elif importrows > currentrows:
grid.AppendRows(new_rows - 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, ColumnCode, "%06o" % code)
grid.SetCellValue(i, ColumnAddress, address)
grid.SetCellValue(i, ColumnLabel, label)
grid.SetCellValue(i, ColumnOpcode, opcode)
grid.SetCellValue(i, ColumnField, field)
i += 1
# add gap if one is next
if addr in gap_addr:
grid.SetCellValue(i, ColumnCode, '')
grid.SetCellValue(i, ColumnAddress, '')
grid.SetCellValue(i, ColumnLabel, '')
grid.SetCellValue(i, ColumnOpcode, '')
grid.SetCellValue(i, ColumnField, '')
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:
if grid.GetCellValue(row, ColumnCode):
addrlist.append(int(grid.GetCellValue(row, ColumnAddress), 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:
if grid.GetCellValue(row, ColumnCode):
addrlist.append(int(grid.GetCellValue(row, ColumnAddress), 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():
if grid.GetCellValue(row, ColumnCode):
addr = int(grid.GetCellValue(row, ColumnAddress), 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]
if grid.GetCellValue(row, ColumnCode):
addrstr = grid.GetCellValue(row, ColumnAddress)
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)
frame.enableUndo(True)
grid.ClearSelection()
def popupClearRef(self, event):
global grid, mem
row = grid.GetSelectedRows()[0]
if grid.GetCellValue(row, ColumnCode):
addrstr = grid.GetCellValue(row, ColumnAddress)
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)
frame.enableUndo(True)
grid.ClearSelection()
def popupDoType(self, event):
global grid, mem
for row in grid.GetSelectedRows():
if grid.GetCellValue(row, ColumnCode):
addrstr = grid.GetCellValue(row, ColumnAddress)
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+1, 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=(400, 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, "Code")
self.grid.SetColSize(0, 65)
self.grid.SetColLabelValue(1, "Address")
self.grid.SetColSize(1, 65)
self.grid.SetColLabelValue(2, "Label")
self.grid.SetColSize(2, 65)
self.grid.SetColLabelValue(3, "Opcode")
self.grid.SetColSize(3, 65)
self.grid.SetColLabelValue(4, "Field")
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.GetPath()
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.GetPath()
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='.', defaultFile='',
wildcard=projwildcard,
style=wx.SAVE | wx.CHANGE_DIR)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
saveProject(filename)
projectName = os.path.basename(filename)
if projectName.endswith(DEFPROJSUFFIX):
projectName = projectName[:-len(DEFPROJSUFFIX)]
dlg.Destroy()
def Menu103(self, event):
global grid, 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.GetPath()
self.grid.ClearGrid()
result = binimport.ptpimport(filename)
if result is not None:
(mem, start, ac) = result
fillGrid(grid, mem)
projectName = os.path.basename(filename)
if projectName.endswith(DEFPTPSUFFIX):
projectName = projectName[:-len(DEFPTPSUFFIX)]
self.enableSaveWrite(True)
mem.clearUndo()
self.enableUndo(False)
if start:
# mark start address as MAIN instructions
self.do_main_start(start & 077777)
dlg.Destroy()
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.GetPath()
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)
def do_main_start(self, start):
"""Mark start address as MAIN opcodes."""
print('do_main_start: start=%06o' % start)
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()