Advertisement
AdityaSriram

up8085.py (v2.0.1)

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