Advertisement
AdityaSriram

up8085.py (v1.0)

Feb 3rd, 2013
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 20.19 KB | None | 0 0
  1. #-------------------------------------------------------------------------------
  2. # Name:        up8085
  3. # Purpose:     Emulate the Dynalog microfriend 8085 microprocessor
  4. #
  5. # Author:      Aditya Sriram
  6. # Version:     1.0
  7. # Created:     31/01/2013
  8. # Copyright:   (c) Cubes and Codes 2013
  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 *
  19. import re, pickle, os, win32api
  20. from led import LED
  21.  
  22. #-------------------------------------------------------------------------------
  23. #============================ Opcode initialization ============================
  24.  
  25. OpCode = pickle.load(open(os.path.join(os.getcwd(), 'OpcodeSheet.pkl')))
  26.  
  27. #-------------------------------------------------------------------------------
  28. #============================ Memory and Registers =============================
  29.  
  30. reg = dict(zip('abcdefhlm',[0x0 for i in 'abcdefhlm']))
  31. mem = {'c000':0x0}
  32. flags = {'s':0,'z':0,'ac':0,'p':0,'cy':0,'-':0}
  33. regPairs = {'h':'l','b':'c','d':'e'}
  34.  
  35. #-------------------------------------------------------------------------------
  36. #============================== General Functions ==============================
  37. def hexStr(n,fill=2):
  38.     return hex(n).replace('0x','').zfill(fill)
  39. #-------------------------------------------------------------------------------
  40. #============================== Class Definitons ===============================
  41.  
  42. class Button:
  43.  
  44.     text = ""
  45.     subText = ""
  46.     key = ""
  47.     master = None
  48.     canvas = None
  49.  
  50.     def __init__(self, master, buttonText, locX, locY, width, height, clickFunc):
  51.         self.canvas = Canvas(master, background='#3C3C3C', height=height, width=width, cursor="hand2")
  52.         self.canvas.place(x=locX, y=locY)
  53.         self.canvas.create_text(width/2, height/2,
  54.                                 font=("Monaco",min(height, width)/3-10),
  55.                                 text=buttonText, fill='white', justify=CENTER)
  56.  
  57.         buttonText = buttonText.split('\n')
  58.         self.text = buttonText[0]
  59.         if len(buttonText) > 1:
  60.             self.subText = buttonText[1]
  61.         self.key = self.text.lower()
  62.         self.master = master
  63.  
  64.         self.canvas.bind('<Enter>', lambda e: self.canvas.config(background='#222222'))
  65.         self.canvas.bind('<Leave>', lambda e: self.canvas.config(background='#3C3C3C'))
  66.         self.canvas.bind('<Button-1>', lambda e: clickFunc(self.key))
  67.  
  68.  
  69. class counter:
  70.     address = ""
  71.     def __init__(self, address):
  72.         self.address = address
  73.     def next(self, increment = 1):
  74.         self.address = hexStr(eval('0x' + self.address) + increment, 4)
  75.         print self.address
  76.     def __call__(self):
  77.         return self.address
  78.     def value(self):
  79.         return eval('0x' + self.address)
  80.  
  81. #-------------------------------------------------------------------------------
  82. #======================== Execution assisting functions ========================
  83. def flagUpdate(affect = 'szpcy',register = 'a'):
  84.     """Updates flags according to current accumulator content.(excluding
  85.    auxiliary carry flag)"""
  86.     global reg,flags
  87.     acc = reg[register]
  88.     flags['s'] = 0b1 if (('s' in affect) and (acc < 0)) else 0b0
  89.     flags['z'] = 0b1 if (('z' in affect) and (acc == 0)) else 0b0
  90.     if (('cy' in affect) and (acc >= 256)):
  91.         flags['cy'] = 0b1
  92.         reg[register] = eval('0b' + bin(acc)[-8:])
  93.         acc = reg[register]
  94.     else:flags['cy'] = 0b0
  95.     if ('p' in affect):
  96.         flags['p'] = 0b1
  97.         for i in bin(acc)[bin(acc).index('b')+1:]:
  98.             if i == '1':
  99.                 flags['p'] = eval(bin(not flags['p']))
  100.  
  101. def negate(number):
  102.     number = bin(number).replace('0b','').zfill(8)
  103.     number = number.replace('1','*1').replace('0','1').replace('*1','0')
  104.     return eval('0b' + number)
  105.  
  106. def move(rd,rs):
  107.     """MOV,MVI command"""
  108.     global mem,reg
  109.     rd = rd.lower()
  110.     if rd in reg and rs in reg:
  111.         rs =rs.lower()
  112.         if (rd == 'm') ^ (rs =='m'):
  113.             if rd =='m':
  114.                 mem[hexStr(reg['h'])+hexStr(reg['l'])] = reg[rs]
  115.             else:
  116.                 reg[rd] = mem[hexStr(reg['h'])+hexStr(reg['l'])]
  117.         elif rd != 'm':
  118.             reg[rd] = reg[rs]
  119.         else: pass
  120.     else:
  121.         reg[rd] =rs
  122.  
  123. def add(operand,cy,operated = 'a'):
  124.     """Operates(adds) on operand provide, with or without carry
  125.    depending on value of carry(0:w/o,1:w/). Result is in accumulator"""
  126.     global mem,reg,flags
  127.     if operand == 'm':operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
  128.     if operand in reg:operand = reg[operand]
  129.     if (((reg[operated] % 16) + (operand % 16)) >= 16):flags['ac']=0b1
  130.     reg[operated] = reg[operated] + operand + cy*flags['cy']
  131.     flagUpdate('szpcy')
  132.  
  133. def sub(operand,borrow,operated = 'a'):
  134.     if operand == 'm':operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
  135.     if operand in reg:
  136.         operand = reg[operand]
  137.     operand = negate(operand + borrow*flags['cy']) + 1
  138.     add(operand,0,operated)
  139.     flags['cy'] = eval(bin(not(flags['cy'])))
  140.     flags['s'] = flags['cy']
  141.  
  142. def bit(oper,rs):
  143.     """Return bitwise operation result of accumulator and register or data
  144.    oper can be:
  145.    0: bit-wise 'and'
  146.    1: bit-wise 'or'
  147.    2: bit-wise 'exor'"""
  148.     global reg,flags
  149.     operlist = [lambda x,y:x&y, lambda x,y:x|y, lambda x,y:x^y]
  150.     if rs in reg:
  151.         if rs == 'm':
  152.             rs = mem[hexStr(reg['h'])+hexStr(reg['l'])]
  153.             bit(oper,rs)
  154.         else:
  155.             reg['a'] = operlist[oper](reg['a'],reg[rs])
  156.     else:
  157.         reg['a'] = operlist[oper](reg['a'],rs)
  158.  
  159. #============================= Executing function ==============================
  160.  
  161. def execute(start):
  162.     global mem,reg,flags,regPairs
  163.     pc = counter(start)
  164.     from time import time
  165.     t = time()
  166.     def getAddr(startFrom):
  167.         """Extract 4 byte address from address locations proceeding given
  168.        startFrom location, lsb then msb"""
  169.         return (hexStr(mem[hexStr(startFrom.value() + 2, 4)]) + hexStr(mem[hexStr(startFrom.value() + 1, 4)]))
  170.  
  171.     while mem[pc()] != 0xcf and (time()-t) <= 15:
  172.         operation = OpCode[mem[pc()]].lower()
  173.         jump = [i in operation for i in ['jz','jnz','jc','jnc','jpe','jpo','jm','jp']]
  174.         if 'mov' in operation:
  175.             move(operation[operation.index(',')-1],operation[-1])
  176.         elif 'mvi' in operation:
  177.             pc.next()
  178.             move(operation[operation.index(',')-1],mem[pc()])
  179.         elif 'lxi' in operation:
  180.             pc.next()
  181.             move(regPairs[operation[-1]],mem[pc()])
  182.             pc.next()
  183.             move(operation[-1],mem[pc()])
  184.         elif 'lda' in operation:
  185.             move('a', mem[getAddr(pc)])
  186.             pc.next(2)
  187.         elif 'sta' in operation:
  188.             mem[getAddr(pc)] = reg['a']
  189.             pc.next(2)
  190.         elif 'lhld' in operation:
  191.             reg['l'] = mem[getAddr(pc)]
  192.             reg['h'] = mem[hexStr(eval(getAddr(pc)) + 1,4)]
  193.             pc.next(2)
  194.         elif 'shld' in operation:
  195.             mem[getAddr(pc)] = reg['l']
  196.             mem[hexStr(eval(getAddr(pc)) + 1,4)] = reg['h']
  197.         elif 'ldax' in operation:
  198.             addr = '0x' + hexStr(reg[operation[-1]]) + hexStr(reg[regPairs[operation[-1]]])
  199.             reg['a'] = mem[addr]
  200.         elif 'stax' in operation:
  201.             addr = '0x' + hexSrt(reg[operation[-1]]) + hexStr(reg[regPairs[operation[-1]]])
  202.             mem[addr] = reg['a']
  203.         elif 'xchg' in operation:
  204.             reg['h'],reg['l'],reg['d'],reg['e'] = reg['d'],reg['e'],reg['h'],reg['l']
  205.         elif 'add' in operation or 'adc' in operation:
  206.             add(operation[-1],1 if 'adc' in operation else 0)
  207.         elif 'adi' in operation or 'aci' in operation:
  208.             pc.next()
  209.             add(mem[pc()],1 if 'aci' in operation else 0)
  210.         elif 'sub' in operation or 'sbb' in operation:
  211.             sub(operation[-1],1 if 'sbb' in operation else 0)
  212.         elif 'sui' in operation or 'sbi' in operation:
  213.             pc.next()
  214.             sub(mem[pc()],1 if 'sbi' in operation else 0)
  215.         elif 'inr' in operation or 'dcr' in operation:
  216.             carry = flags['cy']
  217.             if operation[-1] != 'm':
  218.                 add(1,0,operation[-1])
  219.             elif operation[-1] == 'm':
  220.                 mem[hexStr(reg['h']) + hexStr(reg['l'])] += 1
  221.             else:pass
  222.             flags['cy'] = carry
  223.         elif 'dcr' in operation:
  224.             carry = flags['cy']
  225.             if operation[-1] != 'm':
  226.                 sub(1,0,operation[-1])
  227.             elif operation[-1] == 'm':
  228.                 mem[hexStr(reg['h']) + hexStr(reg['l'])] -=1
  229.             else:pass
  230.         elif 'inx' in operation or 'dcx' in operation:
  231.             pair = '0x' + hexStr(reg[operation[-1]]) + hexStr(reg[regPairs[operation[-1]]])
  232.             pair = hexStr(eval(pair) + (1 if 'inx' in operation else -1))
  233.             reg[operation[-1]],reg[regPairs[operation[-1]]] = eval('0x' + pair[:2]),eval('0x' + pair[2:])
  234.         elif 'dad' in operation:
  235.             reg['l'] += reg[regPairs[operation[-1]]]
  236.             if reg['l'] >= 256:
  237.                 reg['l'] = hexStr(reg['l'])[-2:]
  238.                 flags['cy']= 1
  239.             reg['h'] = reg[operation[-1]] + flags['cy']
  240.             if reg['h'] >= 256:
  241.                 reg['h'] = hexStr(reg['h'])[-2:]
  242.                 flags['cy'] = 1
  243.         elif 'daa' in operation:
  244.             if (flags['ac'] == 1) or not((hexStr(reg['a'])[-1]).isalpha()):reg['a'] += 0x6
  245.             if (flags['cy'] == 1) or not((hexStr(reg['a']).zfill(4))[:2]).isaplha(): reg['a'] += 0x60
  246.             flagUpdate()
  247.         elif 'jmp' in operation:
  248.             pc.address = '0x' + hexStr(eval(getAddr(pc)) - 1,4)
  249.         elif True in jump:
  250.             conditions = [bool(flags['z']),not bool(flags['z']),bool(flags['cy']),not bool(flags['cy']),\
  251.                           bool(flags['p']),not bool(flags['p']),bool(flags['s']) ,not bool(flags['s'])]
  252.             if conditions[jump.index(True)]:
  253.                 pc.address = '0x' + hexStr(eval(getAddr(pc)) - 1,4)
  254.             else:
  255.                 pc.next(2)
  256.         elif 'pchl' in operation:
  257.             pc.address = '0x' + hexStr(reg['h']).zfill(2) + hexStr(reg['l']).zfill(2)
  258.             pc.address = '0x' + hexStr(pc.value() - 1,4)
  259.         elif 'ana' in operation:
  260.             bit(0, (operation[-1] if 'ana' in operation else mem[hexStr(pc.value() + 1,4)]))
  261.             flagUpdate('szp')
  262.             flags['cy'], flags['ac'] = 0, 1
  263.         elif 'ora' in operation or 'ori' in operation:
  264.             bit(1, (operation[-1] if 'ora' in operation else mem[hexStr(pc.value() + 1,4)]))
  265.             flagUpdate('szp')
  266.             flags['cy'], flags['ac'] = 0, 0
  267.         elif 'xra' in operation or 'xri' in operation:
  268.             bit(2, (operation[-1] if 'xra' in operation else mem[hexStr(pc.value() + 1,4)]))
  269.             flagUpdate('szp')
  270.             flags['cy'], flags['ac'] = 0, 0
  271.         elif 'stc' in operation:
  272.             flags['cy'] = 1
  273.         elif 'cma' in operation:
  274.             reg['a'] = negate(reg['a'])
  275.         elif 'cmc' in operation:
  276.             flags['cy'] = int(not flags['cy'])
  277.         elif 'rar' in operation or 'ral' in operation:
  278.             byte = str(flags['cy'])*(operation[-1] == 'r') + bin(reg['a']).replace('0b','').zfill(8) + str(flags['cy'])*(operation[-1] == 'l')
  279.             if 'rar' in operation:
  280.                 reg['a'] = eval('0b' + byte[:-1])
  281.                 flags['cy'] = eval('0b' + byte[-1])
  282.             else:
  283.                 reg['a'] = eval('0b' + byte[1:])
  284.                 flags['cy'] = eval('0b' + byte[0])
  285.         pc.next()
  286.  
  287. #-------------------------------------------------------------------------------
  288. #============================= Interface Functions =============================
  289.  
  290. def drawButtons():
  291.     global buttons, buttonFrame
  292.     numPadText = ['C\nU1','D\nU2','E\nU3','F\nU4',\
  293.                   '8\nGo/H','9\nL','A\nLOAD','B\nSAVE',\
  294.                   '4\nSPH','5\nSPL','6\nPCH','7\nPCL',\
  295.                   '0\nSET','1\nCODE','2\nSTEP','3\nREG']
  296.     opPadText = "VI,DCR,EXEC,INR".split(',')
  297.     gap = 50
  298.     startX, startY = 350, 0
  299.     width, height = 100, 100
  300.     for i in range(4):
  301.         buttons.append(Button(buttonFrame, opPadText[i],
  302.                               startX - width - gap,
  303.                               startY + (height*i),
  304.                               width, height, buttonPress))
  305.     for i in range(4):
  306.         for j in range(4):
  307.             buttons.append(Button(buttonFrame, numPadText[4*i+j],
  308.                                   startX + (width*j),
  309.                                   startY + (height*i),
  310.                                   width, height, buttonPress))
  311.     buttons.append(Button(buttonFrame, "RST",
  312.                           startX - (width*2) - gap, startY,
  313.                           width-2, height-2, buttonPress))
  314.  
  315.  
  316. def update():
  317.     global addressLED, contentLED, address, content
  318.     for i, char in enumerate(address.replace('0x','')):
  319.         addressLED[i].colorSeg(char)
  320.     for i, char in enumerate(content):
  321.         contentLED[i].colorSeg(char)
  322.  
  323. def buttonPress(key):
  324.     global address, content, activeField, mode, mem
  325.     # print "You pressed {}\nMode: {}\nActive:{}".format(key, mode, activeField)
  326.  
  327.     if len(key) < 2 and ('0' <= key <= 'f'): # pressed key is a digt/numpad key
  328.         if mode == "reset":
  329.         # if 'reset' mode then keys have special meaning
  330.         # denoted by text blow the numbers on the keys
  331.             if key == "0": # '0' means 'SET' instruction
  332.                 activeField = "address"
  333.                 #firstEntry = True # the first entry would blank the address
  334.                 address, content = ' '*4, ' '*2
  335.                 mode = "entry"
  336.             elif key == "3": # '3' means 'REG' instruction
  337.                 mode = "reg"
  338.                 activeField = "address"
  339.                 address, content = ' '*4, ' '*2
  340.                 update()
  341.             elif key == "8": # '8' means 'GO' instruction
  342.                 address, content = ' '*4, ' '*2
  343.                 mode = "go"
  344.                 activeField = "address"
  345.             update()
  346.  
  347.         elif mode in ["entry","go"]:
  348.         # if 'entry' mode, the numbers are appended to
  349.         # the respective field denoted by activeField variable
  350.             if activeField == "content":
  351.                 content = (content + key)[1:] # append key to current value
  352.             elif activeField == "address":
  353.                 '''if firstEntry: # if it is first entry clear the earlier value
  354.                    address = ' '*3 + key
  355.                    firstEntry = False
  356.                else:'''
  357.                 address = (address + key)[1:] # append key to current value
  358.             update()
  359.  
  360.         elif mode == "reg":
  361.             if key == "rst":
  362.                 mode = "reset"
  363.                 address, content = 'frie', 'nd'
  364.             elif key in 'abcde':
  365.                 address = ' '*3 + key
  366.                 content = hexStr(reg[key], 2)
  367.             elif key == "8":
  368.                 address = ' '*3 + 'h'
  369.                 content = hexStr(reg['h'], 2)
  370.             elif key == '9':
  371.                 address = ' '*3 + 'l'
  372.                 content = hexStr(reg['l'], 2)
  373.             elif key == 'f':
  374.                 address = ' '*3 + 'f'
  375.                 content = hexStr(eval('0b' + ''.join([str(flags[char]) for char
  376.                                        in 's,z,-,ac,-,p,-,cy'.split(',')])), 2)
  377.             update()
  378.  
  379.     elif key == "inr": # pressed 'INR' key
  380.         if activeField == "address":
  381.             if mode == "reg":
  382.                 address = ' '*3 + ('abcdehlf'[('abcdehlf'.index(address[-1])+1)%8])
  383.                 content = hexStr(reg[address[-1]], 2)
  384.             else:
  385.                 activeField = "content"
  386.                 if mem.has_key(address):
  387.                     content = hexStr(mem[address], 2)
  388.                 else:
  389.                     content, mem[address] = '00', 0
  390.         elif activeField == "content":
  391.             try:
  392.                 mem[address] = int(content, 16)
  393.             except ValueError:
  394.                 address, content = 'ferr', 'or'
  395.             else:
  396.                 address = hexStr(int(address,16) + 1, 4)
  397.                 if mem.has_key(address):
  398.                     content = hexStr(mem[address], 2)
  399.                 else:
  400.                     content, mem[address] = '00', 0
  401.         update()
  402.  
  403.     elif key == 'rst': # pressed 'RST' key
  404.         address, content = "frie", "nd"
  405.         mode = "reset"
  406.         update()
  407.  
  408.     elif key == "dcr": # pressed 'DCR' key
  409.         if activeField == "address":
  410.             if mode == "reg":
  411.                 address = ' '*3 + ('abcdehlf'[('abcdehlf'.index(address[-1])-1)%8])
  412.                 content = hexStr(reg[address[-1]], 2)
  413.             else:
  414.                 activeField = "content"
  415.                 if mem.has_key(address):
  416.                     content = hexStr(mem[address], 2)
  417.                 else:
  418.                     content, mem[address] = '00', 0
  419.         elif activeField == "content":
  420.             mem[address] = int(content, 16)
  421.             address = hexStr(int(address,16) - 1,4)
  422.             if mem.has_key(address):
  423.                 content = hexStr(mem[address], 2)
  424.             else:
  425.                 if address == 'bfff':
  426.                     win32api.MessageBox(0, "You cannot edit memory below C000.",
  427.                                         "Warning")
  428.                     address = 'c000'
  429.                     content = hexStr(mem[address], 2)
  430.                 else:
  431.                     content, mem[address] = '00', 0
  432.         update()
  433.  
  434.     elif key == "exec":
  435.         if mode == "go":
  436.             activeField = ""
  437.             print "Executing from {}".format(address)
  438.             try:
  439.                 execute(address)
  440.             except BaseException as e:
  441.                 address, content = 'ferr', 'or'
  442.                 update()
  443.                 print "\n\n",e.message
  444.             else:
  445.                 buttonPress('rst')
  446.  
  447. #-------------------------------------------------------------------------------
  448. #=============================== User Interface ================================
  449.  
  450. root = Tk()
  451. root.title('8085 Microprocessor simulator')
  452.  
  453. screenHeight, screenWidth = root.winfo_screenheight(), root.winfo_screenwidth()
  454. windowHeight, windowWidth = int(screenHeight*(5/6.0)), int(screenWidth*(2/3.0))
  455. windowPadX, windowPadY = int(screenWidth*(1/6.0)), int(screenHeight*(1/24.0))
  456.  
  457. root.geometry('{}x{}+{}+{}'.format(windowWidth, windowHeight, windowPadX, windowPadY))
  458. root.pack_propagate(False)
  459. root.config(background = 'black')
  460.  
  461. #..................................Key Bindings.................................
  462. def f(e):
  463.     char = e.char
  464.     if char in '0123456789abcdef':
  465.         buttonPress(e.char)
  466.     elif char == '+':
  467.         buttonPress('inr')
  468.     elif char == '-':
  469.         buttonPress('dcr')
  470.  
  471. for char in '0123456789+-abcdef':
  472.     root.bind(char, f)
  473.  
  474. root.bind('<space>', lambda e:buttonPress('rst'))
  475. root.bind('<Return>', lambda e:buttonPress('exec'))
  476. #...............................................................................
  477.  
  478. displayFrame = Frame(root, background = 'black', height=200)
  479. displayFrame.pack(side=TOP, fill=X)
  480.  
  481. buttonFrame = Frame(root, background = 'black')
  482. buttonFrame.pack(side=TOP, fill=BOTH, expand=1)
  483.  
  484. #b1 = Button(buttonFrame, "RST", 50, 50, 75, 75, buttonPress)
  485.  
  486. addressLED = [LED(displayFrame, str(i), 75*i + 200, 25, 75, 150) for i in range(4)]
  487. contentLED = [LED(displayFrame, str(i), 75*i + (200+75*4+25), 25, 75, 150) for i in range(2)]
  488. address = ""
  489. content = ""
  490. activeField = ""
  491. firstEntry = False
  492. mode = 'reset'
  493.  
  494. buttons = []
  495.  
  496. drawButtons()
  497.  
  498. #-------------------------------------------------------------------------------
  499. #============================ Functionality Checks =============================
  500.  
  501. address = "frie"
  502. content = "nd"
  503.  
  504. update()
  505.  
  506. root.mainloop()
  507.  
  508. def main():
  509.     pass
  510.  
  511. if __name__ == '__main__':
  512.     main()
  513.  
  514. #-------------------------------------------------------------------------------
  515.  
  516. # Note:
  517. # Redundant lines: 129-132, 142-145 and 154-163
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement