Advertisement
AdityaSriram

up8085.py (v2.0)

Feb 12th, 2013
202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 33.00 KB | None | 0 0
  1. #-------------------------------------------------------------------------------
  2. # Name:        up8085
  3. # Purpose:     Emulate the Dynalog microfriend 8085 microprocessor
  4. #
  5. # Author:      Aditya Sriram
  6. # Version:     2.0
  7. # Created:     31/01/2013
  8. # Copyright:   (c) 2013 Cubes and Codes
  9. # Licence:     GNU General Public License
  10. #
  11. # View <http://www.youtube.com/watch?v=k8kqdx--SLg> for a demonstration
  12. # of this program
  13. #-------------------------------------------------------------------------------
  14. #!/usr/bin/env python
  15.  
  16. #============================== External Modules ===============================
  17.  
  18. from Tkinter import *      # provides base for GUI
  19. import tkFileDialog, tkMessageBox
  20. import re, pickle, os, sys # regex, file saving/loading, system path
  21. from time import time
  22. from led import LED        # module for LED displays
  23.  
  24. #-------------------------------------------------------------------------------
  25. #============================ Opcode initialization ============================
  26.  
  27. opcode = {} # empty <dict> to store Hex codes and corresponding MatchObjects
  28.  
  29. # regex to capture data from file (format specified below)
  30. template = re.compile(
  31. """
  32. \d+\.              # Serial Number
  33. \ ([A-Z]+)         # Instruction
  34. \ ?([\w-]*),?      # First Operand (optional)
  35. \ ?([\w]*)         # Second Operand (optional)
  36. \ ([A-Z0-9]{2})    # Hex Code
  37. """, re.VERBOSE)
  38.  
  39. # Open file 'opcode.txt' containing all the Opcodes in the following format
  40. #
  41. # <Sr.no.>. <Opcode> <Operand1>, <Operand2> <Hex Code> <Number of bytes>
  42. #
  43. # Examples:
  44. # 1. ACI Data CE 2
  45. # 16. ADD L 85 1
  46. # 30. CM Label FC 3
  47. # 31. CMA 2F 1
  48. # 40. MOV C, L 4D 1
  49. with open(os.path.join(os.getcwd(), r'bin\opcode.txt'), 'r') as f:
  50.     for line in f:
  51.         mo = template.search(line)
  52.  
  53.     # group(4) of MatchObject conains Hex Code which will act as keys
  54.         opcode[int(mo.group(4),16)] = mo
  55.  
  56. #-------------------------------------------------------------------------------
  57. #============================ Memory and Registers =============================
  58.  
  59. reg = {'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'h':0,'l':0,'m':0} # registers
  60. mem = {}                                                      # Memory/RAM
  61. flags = {'s':0,'z':0,'ac':0,'p':0,'cy':0,'-':0}               # flag registers
  62. regPairs = {'h':'l','b':'c','d':'e'}                          # registry *pairs*
  63. stackPointer = 0xf000
  64. programCounter = 0x0000
  65.  
  66. #-------------------------------------------------------------------------------
  67. #============================== General Functions ==============================
  68.  
  69. def hexStr(n, fill=2):
  70.     """Return hexadecimal representation of 'n' as a string without
  71.    '0x' in the beginning and padded with zeroes to form
  72.    'fill' number of characters"""
  73.     return hex(n).replace('0x','').zfill(fill)
  74.  
  75. def binStr(n, fill=8):
  76.     """Return binary representation of 'n' as a string without
  77.    '0b' in the beginning and padded with zeroes to form
  78.    'fill' number of characters"""
  79.     return bin(n).replace('0b','').zfill(fill)
  80.  
  81. #-------------------------------------------------------------------------------
  82. #============================== Class Definitons ===============================
  83.  
  84. class button:
  85.     """Class for managing onscreen buttons, their creation and
  86.    their key bindings"""
  87.  
  88.     text = ""        # Main text to be displayed on the button face
  89.     subText = ""     # Sub-text displayed below main-text
  90.     key = ""         # Key to be passed to binded function for identification
  91.     master = None    # Parent widget
  92.     canvas = None    # main canvas
  93.  
  94.     def __init__(self, master, buttonText, locX, locY, width, height, clickFunc):
  95.         """Initialize button and draw it onto 'master'.
  96.        Parameters:
  97.         |  master: parent Tkinter widget
  98.         |  buttonText: text to be displayed on button face
  99.         |              interprets newline character as delimiter
  100.         |              for main text and sub-text
  101.         |  locX, locY: x and y coordinates of top-left corner of button
  102.         |  width, height: dimensions of button
  103.         |  clickFunc: Function to which mouse-click event will be binded.
  104.         |             This function will be passes 'key' as an identification
  105.         |             of which button was clicked.
  106.        """
  107.         self.canvas = Canvas(master, background='#3C3C3C',
  108.                              height=height, width=width, cursor="hand2")
  109.         self.canvas.place(x=locX, y=locY)
  110.         self.canvas.create_text(width/2, height/2,
  111.                                 font=("Monaco",min(height, width)/3-10),
  112.                                 text=buttonText, fill='white', justify=CENTER)
  113.  
  114.         buttonText = buttonText.split('\n') # separate main text and sub-text
  115.         self.text = buttonText[0]
  116.         if len(buttonText) > 1:
  117.             self.subText = buttonText[1]
  118.         self.key = self.text.lower()
  119.         self.master = master
  120.  
  121.         self.canvas.bind('<Enter>', lambda e: self.canvas.config(background='#222222'))
  122.         self.canvas.bind('<Leave>', lambda e: self.canvas.config(background='#3C3C3C'))
  123.         self.canvas.bind('<Button-1>', lambda e: clickFunc(self.key))
  124.  
  125.  
  126. class circle:
  127.  
  128.     def __init__(self, master, locX, locY, width, height):
  129.         self.canvas = Canvas(master, height=height, width=width, bg='black')
  130.         self.canvas.place(x=locX,y=locY)
  131.         self.canvas.create_oval([3,3,width,height], fill='#200000', tag='dot')
  132.  
  133.     def __call__(self, n):
  134.         if n:
  135.             self.canvas.itemconfig('dot', fill = '#FF0000')
  136.         else:
  137.             self.canvas.itemconfig('dot', fill = '#200000')
  138.  
  139.  
  140. class counter:
  141.     """Class to provide basic Program Counter(PC) functionality."""
  142.  
  143.     address = ""     # address to which counter points
  144.  
  145.     def __init__(self, address):
  146.         """Initialize counter based on address supplied as a hexadecimal
  147.        number string"""
  148.         self.address = address.replace('0x','')
  149.  
  150.     def next(self, increment = 1):
  151.         """Increment address by 'increment' to point to proceeding
  152.        address locations."""
  153.         self.address = hexStr(int(self.address,16) + increment, 4)
  154.         # print self.address #for debugging
  155.  
  156.     def __call__(self):
  157.         """Return current address as a hexadecimal string(without '0x')
  158.        on being called. This allows convenient usage of counter."""
  159.         return self.address
  160.  
  161.     def value(self):
  162.         """Return integer value of hexadecimal address to which it points"""
  163.         return int(self.address,16)
  164.  
  165. #-------------------------------------------------------------------------------
  166. #======================== Execution assisting functions ========================
  167.  
  168. def flagUpdate(affect = 'szpcy',register = 'a'):
  169.     """Updates required flags as specified in 'affect'
  170.    according to 'register' content in <dict> 'reg'
  171.    (cannot handle auxiliary carry flag hence this task is
  172.    assigned to 'add' function.)"""
  173.     global reg,flags
  174.     acc = reg[register]
  175.     if (('cy' in affect) and (acc >= 256)):
  176.         flags['cy'] = 1
  177.         reg[register] = int(binStr(acc)[-8:],2)
  178.         acc = reg[register]
  179.     else:
  180.         flags['cy'] = 0
  181.     if 's' in affect:
  182.         flags['s'] = int(binStr(acc)[0])
  183.     if 'z' in affect:
  184.         flags['z'] = int(acc == 0)
  185.     if 'p' in affect:
  186.         flags['p'] = int(not binStr(acc).count('1')%2)
  187.  
  188. def negate(number, fill=8):
  189.     """Return integer value of 1's complement of number considering
  190.    it as a 'fill' bit number"""
  191.     number = binStr(number, fill)
  192.     number = number.replace('1','*1').replace('0','1').replace('*1','0')
  193.     return int(number,2)
  194.  
  195. def move(rd,rs):
  196.     """Implementation of following instructions
  197.    MOV rd/M, rs/M
  198.    MVI rd, 8-bit Data
  199.    LXI rp
  200.    LDA 16-bit Address
  201.    """
  202.     global mem,reg
  203.     if rd in reg and rs in reg:  # register/M to register/M
  204.         if (rd == 'm') ^ (rs =='m'):
  205.             # XOR to make sure both 'rd','rs' are not 'm'
  206.             # in which case do nothing
  207.             if rd =='m':
  208.                 mem[hexStr(reg['h'])+hexStr(reg['l'])] = reg[rs]
  209.             else:
  210.                 reg[rd] = mem[hexStr(reg['h'])+hexStr(reg['l'])]
  211.         # only both 'm' and both not 'm' cases fall through
  212.         elif rd != 'm':              # confirms none of 'rd', 'rs' is 'm'
  213.             reg[rd] = reg[rs]
  214.     else:                        # content to register(eg. MVI)
  215.         reg[rd] = rs
  216.  
  217. def add(operand,cy,operated = 'a'):
  218.     """Primary implementation of following instructions
  219.        ADD r/M
  220.        ADC r/M
  221.        ADI 8-bit Data
  222.        ACI 8-bit Data
  223.  
  224.    Also provides assistance for 'sub' function
  225.    and following instructions
  226.        INR r/M
  227.        DCR r/M
  228.        DAD rp
  229.        DAA
  230.  
  231.    Adds operand to register 'operated' and handles
  232.    the auxiliary carry flag. 'cy' specifies whether carry is to be added
  233.    depending on value of cy(0->without,1->with). Result is in accumulator"""
  234.     global mem,reg,flags
  235.     if operand == 'm':
  236.         operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
  237.     elif operand in reg:
  238.         operand = reg[operand]
  239.     if operated == 'm':
  240.         reg['m'] = mem[hexStr(reg['h']) + hexStr(reg['l'])]
  241.     if (((reg[operated] % 16) + (operand % 16)) >= 16):
  242.         flags['ac'] = 1
  243.     else:
  244.         flags['ac'] = 0
  245.     reg[operated] = reg[operated] + operand + cy*flags['cy']
  246.     if operated == 'm':
  247.         mem[hexStr(reg['h']) + hexStr(reg['l'])] = reg['m']
  248.  
  249. def sub(operand,borrow,operated = 'a'):
  250.     """Implementation of following instructions
  251.        SUB r
  252.        SBB r
  253.        SUI r
  254.        SBI r
  255.  
  256.    Indirectly carries out addition. 'borrow' determines if
  257.    carry flag is to be considered available for borrowing
  258.    while subtracting."""
  259.     if operand == 'm':
  260.         operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
  261.     if operand in reg:
  262.         operand = reg[operand]
  263.     operand = negate(operand) + 1
  264.     operated = borrow*flags['cy']*256 + reg[operated]
  265.     add(operand,borrow,operated)
  266.     flagUpdate('cy')
  267.     flags['cy'] = int(not(flags['cy']))
  268.  
  269. def bit(operation,rs):
  270.     """Returns bitwise operation result of accumulator and register or data
  271.    'oper' can be:
  272.    0: bit-wise 'and'
  273.    1: bit-wise 'or'
  274.    2: bit-wise 'xor'"""
  275.     global reg,flags
  276.     # List of operations AND, OR, XOR in order
  277.     operlist = [lambda x,y:x&y, lambda x,y:x|y, lambda x,y:x^y]
  278.     if rs in reg:
  279.         if rs == 'm': # ANA M, ORA M, XRA M
  280.             rs = mem[hexStr(reg['h'])+hexStr(reg['l'])]
  281.             bit(operation,rs)
  282.         else:         # ANA r, ORA r, XRA r
  283.             reg['a'] = operlist[operation](reg['a'],reg[rs])
  284.     else:             # ANI, ORI, XRI
  285.         reg['a'] = operlist[operation](reg['a'],rs)
  286.  
  287. def getFlags():
  288.     """Combines flag-bits to form a return a single
  289.    8-bit hexadecimal number string(without '0x').
  290.    Format: s z - ac - p - cy"""
  291.     global flags
  292.     s = ''.join([str(flags[char]) for char in flagList])
  293.     return hexStr(int(s,2), 2)
  294.  
  295. def setFlags(n):
  296.     """Sets flag-bits to individual bit obtained from
  297.    converting given number to binary.
  298.    Format: s z - ac - p cy"""
  299.     global flags
  300.     s = binStr(n,8)
  301.     for i,char in enumerate(flagList):
  302.         flags[char] = int(s[i])
  303.  
  304. def shift(direction, num, fill):
  305.     """Shifts 'num' in given 'direction' bit-wise after
  306.    padding it with zeroes till 'fill' number of characters"""
  307.     byte = binStr(num, fill)
  308.     if direction == 'r':
  309.         byte = byte[-1] + byte[:-1]
  310.     elif direction == 'l':
  311.         byte = byte[1:] + byte[0]
  312.     return int(byte,2)
  313.  
  314. #============================= Executing function ==============================
  315.  
  316. def execute(start):
  317.     """Function to execute program stored in global variable
  318.    'mem' starting from memory location given by 'start' as
  319.    a hexadecimal string.
  320.  
  321.    Forms the core of this application. It basically is a long
  322.    if-elif clause converting each memory location hexadecimal
  323.    content to the corresponding instruction using global variable
  324.    'opcode' which contains instructions fetched from file
  325.    'opcode.txt' as Regex MatchObjects.
  326.  
  327.  
  328.    Instructions not yet implemented:
  329.    (and probably won't ever be implemented)
  330.    IN port
  331.    OUT port
  332.    EI
  333.    DI
  334.    RIM
  335.    SIM"""
  336.  
  337.     global mem, reg, flags, regPairs, programCounter, stackPointer
  338.     pc = counter(start)     # initialize counter from 'start' address
  339.     timeSlice, t = 15, time()
  340.     running = True
  341.  
  342.     def getAddr(startFrom):
  343.         """Extract 4 byte address from address locations proceeding given
  344.        'startFrom' location in the memory, lsb then msb"""
  345.         return (hexStr(mem[hexStr(startFrom.value() + 2, 4)]) +
  346.                 hexStr(mem[hexStr(startFrom.value() + 1, 4)]))
  347.     flaggers =['z', 'nz', 'c', 'nc', 'pe', 'po', 'm', 'p']
  348.     jumpers = [ 'jmp']+['j' + i for i in flaggers]
  349.     callers = ['call']+['c' + i for i in flaggers]
  350.     returns = [ 'ret']+['r' + i for i in flaggers]
  351.  
  352.     while running and (time()-t <= timeSlice):
  353.         instruction, op1, op2 = [opcode[mem[pc()]].group(i).lower() for i in [1,2,3]]
  354.         print instruction, op1, op2
  355.         if instruction == 'mov':
  356.             move(op1,op2)
  357.         elif instruction == 'mvi':
  358.             pc.next()
  359.             move(op1,mem[pc()])
  360.         elif instruction == 'lxi':
  361.             pc.next()
  362.             move(regPairs[op1],mem[pc()])
  363.             pc.next()
  364.             move(op1,mem[pc()])
  365.         elif instruction == 'ldax':
  366.             addr = hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
  367.             reg['a'] = mem[addr]
  368.         elif instruction == 'stax':
  369.             addr = hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
  370.             mem[addr] = reg['a']
  371.         elif instruction == 'lda':
  372.             move('a', mem[getAddr(pc)])
  373.             pc.next(2)
  374.         elif instruction == 'sta':
  375.             mem[getAddr(pc)] = reg['a']
  376.             pc.next(2)
  377.         elif instruction == 'lhld':
  378.             reg['l'] = mem[getAddr(pc)]
  379.             reg['h'] = mem[hexStr(int(getAddr(pc),16) + 1,4)]
  380.             pc.next(2)
  381.         elif instruction == 'shld':
  382.             mem[getAddr(pc)] = reg['l']
  383.             mem[hexStr(int(getAddr(pc),16) + 1,4)] = reg['h']
  384.         elif instruction == 'xchg':
  385.             reg['h'],reg['l'],reg['d'],reg['e'] = reg['d'],reg['e'],reg['h'],reg['l']
  386.         elif instruction in ['add','adc']:
  387.             add(op1, instruction=='adc')
  388.             flagUpdate()
  389.         elif instruction in ['adi','aci']:
  390.             pc.next()
  391.             add(mem[pc()],instruction=='aci')
  392.             flagUpdate()
  393.         elif instruction in ['sub','sbb']:
  394.             sub(op1,instruction=='sbb')
  395.             flagUpdate('szp')
  396.         elif instruction in ['sui','sbi']:
  397.             pc.next()
  398.             sub(mem[pc()],instruction=='sbi')
  399.             flagUpdate('szp')
  400.         elif  instruction == 'inr':
  401.             add(1, 0, op1)
  402.             carry = flags['cy']
  403.             flagUpdate('szpcy',op1)
  404.             flags['cy'] = carry
  405.         elif instruction == 'dcr':
  406.             add(0xff, 0, op1)
  407.             carry = flags['cy']
  408.             flagUpdate('szpcy',op1)
  409.             flags['cy'] = carry
  410.         elif instruction in ['inx','dcx']:
  411.             pair = hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
  412.             pair = hexStr(int(pair,16) + [1,-1][instruction=='dcx'])
  413.             reg[op1],reg[regPairs[op1]] = int(pair[:2],16),int(pair[2:],16)
  414.         elif instruction == 'dad':
  415.             reg['l'] += reg[regPairs[op1]]
  416.             if reg['l'] >= 256:
  417.                 reg['l'] = int(bin(reg['l'])[-8:],2)
  418.                 add(1,0,'h')
  419.                 flagUpdate('cy','h')
  420.             reg['h'] += reg[op1]
  421.             flagUpdate('cy','h')
  422.         elif instruction == 'daa':
  423.             if flags['ac'] or ((hexStr(reg['a']))[-1]).isalpha():
  424.                 add(6, 0)
  425.             if flags['cy'] or ((hexStr(reg['a']))[0]).isalpha():
  426.                 add(0x60, 0)
  427.             flagUpdate()
  428.         elif instruction == 'jmp':
  429.             pc.address = hexStr(int(getAddr(pc),16) - 1,4)
  430.         elif instruction in jumpers + callers + returns:
  431.             conditions = [True,\
  432.                           bool(flags['z']) , not bool(flags['z']) ,\
  433.                           bool(flags['cy']), not bool(flags['cy']),\
  434.                           bool(flags['p']) , not bool(flags['p']) ,\
  435.                           bool(flags['s']) , not bool(flags['s'])]
  436.             if instruction in jumpers:
  437.                 if conditions[jumpers.index(instruction)]:
  438.                     pc.address = hexStr(int(getAddr(pc),16)-1, 4)
  439.                 else:
  440.                     pc.next(2)
  441.             elif instruction in callers:
  442.                 if conditions[callers.index(instruction)]:
  443.                     mem[hexStr(stackPointer - 1, 4)] = pc.value()/0x100
  444.                     mem[hexStr(stackPointer - 2, 4)] = pc.value()%0x100
  445.                     stackPointer -= 2
  446.                     pc.address = hexStr(getAddr(pc)-1, 4)
  447.                 else:
  448.                     pc.next(2)
  449.             elif instruction in returns:
  450.                 if conditions[returns.index(instruction)]:
  451.                     pc.address = hexStr(mem[hexStr(stackPointer,4)])+ \
  452.                                  hexStr(mem[hexStr(stackPointer + 1)] - 1)
  453.                     stackPointer += 2
  454.                 else:
  455.                     pc.next(2)
  456.         elif instruction == 'pchl':
  457.             pc.address = hexStr(reg['h'], 2) + hexStr(reg['l'], 2)
  458.             pc.address = hexStr(pc.value() - 1,4)
  459.         elif instruction == 'xthl':
  460.             reg['l'], mem[hexStr(stackPointer,4)] = mem[hexStr(stackPointer,4)], reg['l']
  461.             reg['h'], mem[hexStr(stackPointer+1,4)] = mem[hexStr(stackPointer+1,4)], reg['h']
  462.         elif instruction == 'sphl':
  463.             stackPointer = int(hexStr(reg['h']) + hexStr(reg['l']), 16)
  464.         elif instruction == 'push':
  465.             if op1 == 'psw':
  466.                 mem[hexStr(stackPointer-1, 4)] = reg['a']
  467.                 mem[hexStr(stackPointer-2, 4)] = int(getFlags(),16)
  468.             else:
  469.                 mem[hexStr(stackPointer-1, 4)] = reg[op1]
  470.                 mem[hexStr(stackPointer-2, 4)] = reg[regPairs[op1]]
  471.             stackPointer -= 2
  472.         elif instruction == 'pop':
  473.             if op1 == 'psw':
  474.                 setFlags(mem[hexStr(stackPointer, 4)])
  475.                 reg['a']           = mem[hexStr(stackPointer+1, 4)]
  476.             else:
  477.                 reg[regPairs[op1]] = mem[hexStr(stackPointer, 4)]
  478.                 reg[op1]           = mem[hexStr(stackPointer+1, 4)]
  479.             stackPointer += 2
  480.         elif instruction in ['ana','ani']:
  481.             bit(0, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='ani']))
  482.             flagUpdate('szp')
  483.             flags['cy'], flags['ac'] = 0, 1
  484.         elif instruction in ['ora','ori']:
  485.             bit(1, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='ori']))
  486.             flagUpdate('szp')
  487.             flags['cy'], flags['ac'] = 0, 0
  488.         elif instruction in ['xra','xri']:
  489.             bit(2, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='xri']))
  490.             flagUpdate('szp')
  491.             flags['cy'], flags['ac'] = 0, 0
  492.         elif instruction == 'cmp':
  493.             if op1 == 'm':
  494.                 m = mem[hexStr(reg['h'])+hexStr(reg['l'])]
  495.                 flags['cy'] = int(reg['a'] < m)
  496.                 flags['z'] = int(reg['a'] == m)
  497.             else:
  498.                 flags['cy'] = int(reg['a'] < reg[op1])
  499.                 flags['z'] = int(reg['a'] == reg[op1])
  500.         elif instruction == 'cpi':
  501.             op1 = mem[hexStr(pc.value() + 1, 4)]
  502.             flags['cy'] = int(reg['a'] < op1)
  503.             flags['z'] = int(reg['a'] == op1)
  504.         elif instruction == 'rlc':
  505.             reg['a'] = shift('l', reg['a'], 8)
  506.             flags['cy'] = binStr(reg['a'])[-1]
  507.         elif instruction == 'rrc':
  508.             reg['a'] = shift('r', reg['a'], 8)
  509.             flags['cy'] = binStr(reg['a'])[0]
  510.         elif instruction == 'ral':
  511.             reg['a'] = shift('l', reg['a'], 8)
  512.             carry, flags['cy'] = flags['cy'], int(binStr(reg['a'])[-1])
  513.             reg['a'] = int(binStr(reg['a'],2)[:-1] + str(carry))
  514.         elif instruction == 'rar':
  515.             reg['a'] = shift('r', reg['a'], 8)
  516.             carry, flags['cy'] = flags['cy'], int(binStr(reg['a'])[0])
  517.             reg['a'] = int(str(carry) + binStr(reg['a'])[1:], 2)
  518.         elif instruction == 'cma':
  519.             reg['a'] = negate(reg['a'])
  520.         elif instruction == 'cmc':
  521.             flags['cy'] = int(not flags['cy'])
  522.         elif instruction == 'stc':
  523.             flags['cy'] = 1
  524.         elif instruction in ['rst','hlt']:
  525.             running = False
  526.         programCounter = pc.value()
  527.         pc.next()
  528.     programCounter = pc.value() + 1
  529.  
  530. #-------------------------------------------------------------------------------
  531. #============================= Interface Functions =============================
  532.  
  533. def drawButtons():
  534.     global buttons, buttonFrame
  535.     numPadText = ['C\nU1','D\nU2','E\nU3','F\nU4',\
  536.                   '8\nGo/H','9\nL','A\nLOAD','B\nSAVE',\
  537.                   '4\nSPH','5\nSPL','6\nPCH','7\nPCL',\
  538.                   '0\nSET','1\nCODE','2\nSTEP','3\nREG']
  539.     opPadText = "VI,DCR,EXEC,INR".split(',')
  540.     gap = 50
  541.     startX, startY = 350, 0
  542.     width, height = 100, 100
  543.     for i in range(4):
  544.         buttons.append(button(buttonFrame, opPadText[i],
  545.                               startX - width - gap,
  546.                               startY + (height*i),
  547.                               width, height, buttonPress))
  548.     for i in range(4):
  549.         for j in range(4):
  550.             buttons.append(button(buttonFrame, numPadText[4*i+j],
  551.                                   startX + (width*j),
  552.                                   startY + (height*i),
  553.                                   width, height, buttonPress))
  554.     buttons.append(button(buttonFrame, "RST",
  555.                           startX - (width*2) - gap, startY,
  556.                           width-2, height-2, buttonPress))
  557.  
  558. def update(add=None):
  559.     global addressLED, contentLED, addDot, conDot, address, content, mem
  560.     if not add:
  561.         for i in range(4):
  562.             addressLED[i].colorSeg(address[len(address)-4+i])
  563.         for i in range(2):
  564.             contentLED[i].colorSeg(content[len(content)-2+i])
  565.         addDot(activeField=='address')
  566.         conDot(activeField=='content')
  567.  
  568.     else:
  569.         if mem.has_key(add):
  570.             content = hexStr(mem[add])
  571.         else:
  572.             content, mem[add] = '00', 0
  573.         update()
  574.  
  575. def showHelp(e):
  576.     helpText = """
  577.    Press F1 to view help... You probably already know that.
  578.  
  579.    Key-mapping:
  580.    -----------
  581.    =>Keys "0" through "9"(normal or number-pad) mean "0" through
  582.      '9' on the on-screen numpad.
  583.  
  584.    =>"Space-bar" translates to the "RST" key
  585.  
  586.    =>Keys "+" and "-" stand for "INR" and "DCR" keys respectively
  587.  
  588.    =>"Enter" or "Return" key means "EXEC"
  589.  
  590.  
  591.    The "VI" key is just for realism, and does nothing but sit
  592.    and change it's color on being awakened by the pointy white
  593.    arrow you manipulate using a device which resembles a nasty
  594.    rodent.
  595.  
  596.  
  597.                                               Made by
  598.                                               -Aditya Sriram
  599.                                               (a.k.a P.R.Vaidyanathan)
  600.    """
  601.     tkMessageBox.askokcancel("Help", helpText)
  602.     print "A good deed a day"
  603.  
  604. def buttonPress(key):
  605.     print key
  606.     global address, content, activeField, mode, mem, regList, regKeys, regCount
  607.     global stackPointer, programCounter, flagList
  608.  
  609.     # print "You pressed {}\nMode: {}\nActive:{}".format(key, mode, activeField)
  610.  
  611.     if len(key) < 2 and ('0' <= key <= 'f'): # pressed key is a digt/numpad key
  612.         if mode == "reset":
  613.         # if 'reset' mode then keys have special meaning
  614.         # denoted by text blow the numbers on the keys
  615.             if key == "0": # '0' means 'SET' instruction
  616.                 activeField = "address"
  617.                 #firstEntry = True # the first entry would blank the address
  618.                 address, content = ' '*4, ' '*2
  619.                 mode = "entry"
  620.             elif key == "3": # '3' means 'REG' instruction
  621.                 mode = "reg"
  622.                 activeField = "address"
  623.                 address, content = ' '*4, ' '*2
  624.                 update()
  625.             elif key == "8": # '8' means 'GO' instruction
  626.                 address, content = ' '*4, ' '*2
  627.                 mode = "go"
  628.                 activeField = "address"
  629.             elif key == "b": # 'B' means 'SAVE' instruction
  630.                 root.iconify()
  631.                 root.update()
  632.                 f = tkFileDialog.asksaveasfile(mode = "w",
  633.                                  initialdir = os.path.join(os.getcwd(), "bin"),
  634.                                  defaultextension = '.dam',
  635.                                  filetypes = [("Data Assisting Microprocessor", '.dam')])
  636.                 if f:
  637.                     pickle.dump((mem, stackPointer), f)
  638.                     print "Saved successfully"
  639.                     f.close()
  640.                 else:
  641.                     tkMessageBox.askokcancel("File Not Saved",
  642.                     "The file could not be saved.\nPress the \
  643. 'SAVE' button to try saving again.")
  644.                 root.deiconify()
  645.             elif key == "a": # 'A' means 'LOAD' instruction
  646.                 root.iconify()
  647.                 root.update()
  648.                 #fname = raw_input("Enter the name of the file to be loaded\n")
  649.                 f = tkFileDialog.askopenfile(mode = "r",
  650.                                  initialdir = os.path.join(os.getcwd(),"bin"),
  651.                                  filetypes = [('Data Assisting Microprocessor', '.dam')])
  652.                 try:
  653.                     temp = pickle.load(f)
  654.                     if isinstance(temp, dict):
  655.                         mem = temp
  656.                     elif isinstance(temp, tuple):
  657.                         mem, stackPointer = temp
  658.                 except AttributeError:
  659.                     tkMessageBox.askokcancel("No File Selected",
  660.                     "You have not selected any file so no file was \
  661. loaded.\n Press 'LOAD' again if you want to load a file")
  662.                 else:
  663.                     print "Loaded successfully"
  664.                     f.close()
  665.                 root.deiconify()
  666.                 root.update()
  667.             update()
  668.  
  669.         elif mode in ["entry","go"]:
  670.         # if 'entry' mode, the numbers are appended to
  671.         # the respective field denoted by activeField variable
  672.             if activeField == "content":
  673.                 content = (content + key)[1:] # append key to current value
  674.             elif activeField == "address":
  675.                 address = (address + key)[1:] # append key to current value
  676.             update()
  677.  
  678.         elif mode == "reg":
  679.             if key == "rst":
  680.                 mode = "reset"
  681.                 address, content = 'frie', 'nd'
  682.                 activeField = ""
  683.             elif activeField == "address":
  684.                 if key in 'abcde':
  685.                     address = ' '*3 + key
  686.                     content = hexStr(reg[key], 2)
  687.                 elif key == "8":
  688.                     address = ' '*3 + 'h'
  689.                     content = hexStr(reg['h'], 2)
  690.                 elif key == '9':
  691.                     address = ' '*3 + 'l'
  692.                     content = hexStr(reg['l'], 2)
  693.                 elif key == 'f':
  694.                     address = ' '*3 + 'f'
  695.                     content = getFlags()
  696.                 elif key == '4':
  697.                     address = ' sph'
  698.                     content = hexStr(stackPointer/0x100)
  699.                 elif key == '5':
  700.                     address = ' spl'
  701.                     content = hexStr(stackPointer%0x100)
  702.                 elif key == '6':
  703.                     address = ' pch'
  704.                     content = hexStr(programCounter/0x100)
  705.                 elif key == '7':
  706.                     address = ' pcl'
  707.                     content = hexStr(programCounter%0x100)
  708.                 regCount = regKeys.index(key)
  709.                 activeField = "content"
  710.             elif activeField == "content":
  711.                 content = (content + key)[1:]
  712.             update()
  713.  
  714.  
  715.     elif key in ["inr","dcr"]: # pressed 'INR' key
  716.         diff = 1 if key == "inr" else -1
  717.         if activeField == "address":
  718.             activeField = "content"
  719.             update(address)
  720.         elif activeField == "content":
  721.             if mode == "reg":
  722.                 if regList[regCount] in reg.keys():
  723.                     reg[regList[regCount]] = int(content,16)
  724.                 else:
  725.                     if regList[regCount] == 'f':
  726.                         for i,k in enumerate(binStr(int(content,16))):
  727.                             flags[flagList[i]] = int(k)
  728.                     elif regList[regCount] == 'sph':
  729.                         stackPointer = int(content + hexStr(stackPointer%0x100),16)
  730.                     elif regList[regCount] == 'spl':
  731.                         stackPointer = int(hexStr(stackPointer/0x100) + content,16)
  732.                     elif regList[regCount] == 'pch':
  733.                         programCounter = int(content + hexStr(programCounter%0x100),16)
  734.                     elif regList[regCount] == 'pcl':
  735.                         programCounter = int(hexStr(programCounter/0x100) + content,16)
  736.                 activeField = "address"
  737.                 regCount = (regCount + diff)%12
  738.                 buttonPress(regKeys[regCount])
  739.             else:
  740.                 try:
  741.                     mem[address] = int(content, 16)
  742.                 except ValueError:
  743.                     address, content = 'ferr', 'or'
  744.                     update()
  745.                 else:
  746.                     address = hexStr(int(address,16) + diff, 4)
  747.                     update(address)
  748.  
  749.     elif key == 'rst': # pressed 'RST' key
  750.         address, content = "frie", "nd"
  751.         mode = "reset"
  752.         activeField = ""
  753.         update()
  754.  
  755.     elif key == "exec":
  756.         if mode == "go":
  757.             activeField = ""
  758.             pc = address
  759.             #print "Executing from {}".format(pc)
  760.             address = '   e'
  761.             update()
  762.             root.update()
  763.             t = time()
  764.             try:
  765.                 execute(pc)
  766.             except:
  767.                 address, content = 'ferr', 'or'
  768.                 update()
  769.                 print "\nUnexpected Error: ", sys.exc_info()
  770.             else:
  771.                 print "Time taken: {}".format(time()-t)
  772.                 buttonPress('rst')
  773.             execute(pc)
  774.  
  775. #-------------------------------------------------------------------------------
  776. #=============================== User Interface ================================
  777.  
  778. root = Tk()
  779. root.title('8085 Microprocessor simulator')
  780.  
  781. screenHeight, screenWidth = root.winfo_screenheight(), root.winfo_screenwidth()
  782. windowHeight, windowWidth = int(screenHeight*(5/6.0)), int(screenWidth*(2/3.0))
  783. windowPadX, windowPadY = int(screenWidth*(1/6.0)), int(screenHeight*(1/24.0))
  784.  
  785. root.geometry('{}x{}+{}+{}'.format(windowWidth, windowHeight, windowPadX, windowPadY))
  786. root.pack_propagate(False)
  787. root.config(background = 'black')
  788.  
  789. displayFrame = Frame(root, background = 'black', height=200)
  790. displayFrame.pack(side=TOP, fill=X)
  791.  
  792. buttonFrame = Frame(root, background = 'black')
  793. buttonFrame.pack(side=TOP, fill=BOTH, expand=1)
  794.  
  795. #-------------------------------------------------------------------------------
  796. #================================ Key Bindings =================================
  797.  
  798. def f(e):
  799.     char = e.char
  800.     if char == '+':
  801.         buttonPress('inr')
  802.     elif char == '-':
  803.         buttonPress('dcr')
  804.     else:
  805.         buttonPress(e.char.lower())
  806.  
  807. for char in '0123456789+-abcdefABCDEF':
  808.     root.bind(char, f)
  809.  
  810. root.bind('<space>', lambda e:buttonPress('rst'))
  811. root.bind('<Return>', lambda e:buttonPress('exec'))
  812. root.protocol("WM_DELETE_WINDOW", root.destroy)
  813. root.bind('<F1>', showHelp)
  814.  
  815. #-------------------------------------------------------------------------------
  816. #========================= Interface Related Variables =========================
  817.  
  818. addressLED = [LED(displayFrame, str(i), 75*i + 200, 25, 75, 150) for i in range(4)]
  819. addDot = circle(displayFrame, 505, 160, 15, 15)
  820. contentLED = [LED(displayFrame, str(i), 75*i + (200+75*4+25), 25, 75, 150) for i in range(2)]
  821. conDot = circle(displayFrame, 680, 160, 15, 15)
  822. address = "frie"
  823. content = "nd"
  824. activeField = ""
  825.  
  826. firstEntry = False
  827. mode = 'reset'
  828.  
  829. # chronological list of all registers, sp and pc and their keys
  830. regList = ['a','b','c','d','e','f','h','l','sph','spl','pch','pcl']
  831. regKeys = ['a','b','c','d','e','f','8','9',  '4',  '5',  '6',  '7']
  832. regCount = 0
  833.  
  834. flagList = ['s','z','-','ac','-','p','-','cy']
  835.  
  836. buttons = []
  837.  
  838. #-------------------------------------------------------------------------------
  839. #============================ Functionality Checks =============================
  840.  
  841. update()
  842.  
  843. def main():
  844.     drawButtons()
  845.     root.mainloop()
  846.  
  847. if __name__ == '__main__':
  848.     main()
  849.  
  850. #-------------------------------------------------------------------------------
  851.  
  852. # Todo3  Assembler
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement