Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #-------------------------------------------------------------------------------
- # Name: up8085
- # Purpose: Emulate the Dynalog microfriend 8085 microprocessor
- #
- # Author: Aditya Sriram
- # Version: 1.1
- # Created: 31/01/2013
- # Copyright: (c) 2013 Cubes and Codes
- # Licence: GNU General Public License
- #
- # View <http://www.youtube.com/watch?v=k8kqdx--SLg> for a demonstration
- # of this program
- #-------------------------------------------------------------------------------
- #!/usr/bin/env python
- #============================== External Modules ===============================
- from Tkinter import * # provides base for GUI
- import re, pickle, os, sys # regex, file saving/loading, system path
- from time import time,sleep
- from led import LED # module for LED displays
- #-------------------------------------------------------------------------------
- #============================ Opcode initialization ============================
- opcode = {} # empty <dict> to store Hex codes and corresponding MatchObjects
- # regex to capture data from file (format specified below)
- template = re.compile(
- """
- \d+\. # Serial Number
- \ ([A-Z]+) # Instruction
- \ ?([\w-]*),? # First Operand (optional)
- \ ?([\w]*) # Second Operand (optional)
- \ ([A-Z0-9]{2}) # Hex Code
- """, re.VERBOSE)
- # Open file 'opcode.txt' containing all the Opcodes in the following format
- #
- # <Sr.no.>. <Opcode> <Operand1>, <Operand2> <Hex Code> <Number of bytes>
- #
- # Examples:
- # 1. ACI Data CE 2
- # 16. ADD L 85 1
- # 30. CM Label FC 3
- # 31. CMA 2F 1
- # 40. MOV C, L 4D 1
- with open(os.path.join(os.getcwd(), r'bin\opcode.txt'), 'r') as f:
- for line in f:
- mo = template.search(line)
- # group(4) of MatchObject conains Hex Code which will act as keys
- opcode[int(mo.group(4),16)] = mo
- #-------------------------------------------------------------------------------
- #============================ Memory and Registers =============================
- reg = {'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'h':0,'l':0,'m':0} # registers
- mem = {} # Memory/RAM
- flags = {'s':0,'z':0,'ac':0,'p':0,'cy':0,'-':0} # flag registers
- regPairs = {'h':'l','b':'c','d':'e'} # registry *pairs*
- #-------------------------------------------------------------------------------
- #============================== General Functions ==============================
- def hexStr(n, fill=2):
- """Return hexadecimal representation of 'n' as a string without
- '0x' in the beginning and padded with zeroes to form
- fill number of characters"""
- return hex(n).replace('0x','').zfill(fill)
- def binStr(n, fill=8):
- """Return binary representation of 'n' as a string without
- '0b' in the beginning and padded with zeroes to form
- 'fill' number of characters"""
- return bin(n).replace('0b','').zfill(fill)
- #-------------------------------------------------------------------------------
- #============================== Class Definitons ===============================
- class Button:
- """Class for managing onscreen buttons, their creation and
- their key bindings"""
- text = "" # Main text to be displayed on the button face
- subText = "" # Sub-text displayed below main-text
- key = "" # Key to be passed to binded function for identification
- master = None # Parent widget
- canvas = None # main canvas
- def __init__(self, master, buttonText, locX, locY, width, height, clickFunc):
- """Initialize button and draw it onto 'master'.
- Parameters:
- | master: parent Tkinter widget
- | buttonText: text to be displayed on button face
- | interprets newline character as delimiter
- | for main text and sub-text
- | locX, locY: x and y coordinates of top-left corner of button
- | width, height: dimensions of button
- | clickFunc: Function to which mouse-click event will be binded.
- | This function will be passes 'key' as an identification
- | of which button was clicked.
- """
- self.canvas = Canvas(master, background='#3C3C3C',
- height=height, width=width, cursor="hand2")
- self.canvas.place(x=locX, y=locY)
- self.canvas.create_text(width/2, height/2,
- font=("Monaco",min(height, width)/3-10),
- text=buttonText, fill='white', justify=CENTER)
- buttonText = buttonText.split('\n') # separate main text and sub-text
- self.text = buttonText[0]
- if len(buttonText) > 1:
- self.subText = buttonText[1]
- self.key = self.text.lower()
- self.master = master
- self.canvas.bind('<Enter>', lambda e: self.canvas.config(background='#222222'))
- self.canvas.bind('<Leave>', lambda e: self.canvas.config(background='#3C3C3C'))
- self.canvas.bind('<Button-1>', lambda e: clickFunc(self.key))
- class counter:
- """Class to provide basic Program Counter(PC) functionality."""
- address = "" # address to which counter points
- def __init__(self, address):
- """Initialize counter based on address supplied as a hexadecimal
- number string"""
- self.address = address.replace('0x','')
- def next(self, increment = 1):
- """Increment address by 'increment' to point to proceeding
- address locations."""
- self.address = hexStr(eval('0x' + self.address) + increment, 4)
- # print self.address #for debugging
- def __call__(self):
- """Return current address as a hexadecimal string(without '0x')
- on being called. This allows convenient usage of counter."""
- return self.address
- def value(self):
- """Return integer value of hexadecimal address to which it points"""
- return eval('0x' + self.address)
- #-------------------------------------------------------------------------------
- #======================== Execution assisting functions ========================
- def flagUpdate(affect = 'szpcy',register = 'a'):
- """Updates required flags as specified in 'affect'
- according to 'register' content in <dict> 'reg'
- (cannot handle auxiliary carry flag hence this task is
- assigned to 'add' function.)"""
- global reg,flags
- acc = reg[register]
- if (('cy' in affect) and (acc >= 256)):
- flags['cy'] = 1
- reg[register] = eval('0b' + binStr(acc)[-8:])
- acc = reg[register]
- else:
- flags['cy'] = 0
- if 's' in affect:
- flags['s'] = int(binStr(acc)[0])
- if 'z' in affect:
- flags['z'] = int(acc == 0)
- if 'p' in affect:
- flags['p'] = int(not binStr(acc).count('1')%2)
- def negate(number, fill=8):
- """Return integer value of 1's complement of number considering
- it as a 'fill' bit number"""
- number = binStr(number, fill)
- number = number.replace('1','*1').replace('0','1').replace('*1','0')
- return eval('0b' + number)
- def move(rd,rs):
- """Implementation of following instructions
- MOV rd/M, rs/M
- MVI rd, 8-bit Data
- LXI rp
- LDA 16-bit Address
- """
- global mem,reg
- if rd in reg and rs in reg: # register/M to register/M
- if (rd == 'm') ^ (rs =='m'):
- # XOR to make sure both 'rd','rs' are not 'm'
- # in which case do nothing
- if rd =='m':
- mem[hexStr(reg['h'])+hexStr(reg['l'])] = reg[rs]
- else:
- reg[rd] = mem[hexStr(reg['h'])+hexStr(reg['l'])]
- # only both 'm' and both not 'm' cases fall through
- elif rd != 'm': # confirms none of 'rd', 'rs' is 'm'
- reg[rd] = reg[rs]
- else: # content to register(eg. MVI)
- reg[rd] = rs
- def add(operand,cy,operated = 'a'):
- """Primary implementation of following instructions
- ADD r/M
- ADC r/M
- ADI 8-bit Data
- ACI 8-bit Data
- Also provides assistance for 'sub' function
- and following instructions
- INR r/M
- DCR r/M
- DAD rp
- DAA
- Adds operand to register 'operated' and handles
- the auxiliary carry flag. 'cy' specifies whether carry is to be added
- depending on value of cy(0->without,1->with). Result is in accumulator"""
- global mem,reg,flags
- if operand == 'm':
- operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
- elif operand in reg:
- operand = reg[operand]
- if operated == 'm':
- reg['m'] = mem[hexStr(reg['h']) + hexStr(reg['l'])]
- if (((reg[operated] % 16) + (operand % 16)) >= 16):
- flags['ac'] = 1
- else:
- flags['ac'] = 0
- reg[operated] = reg[operated] + operand + cy*flags['cy']
- if operated == 'm':
- mem[hexStr(reg['h']) + hexStr(reg['l'])] = reg['m']
- def sub(operand,borrow,operated = 'a'):
- """Implementation of following instructions
- SUB r
- SBB r
- SUI r
- SBI r
- Indirectly carries out addition. 'borrow' determines if
- carry flag is to be considered available for borrowing
- while subtracting."""
- if operand == 'm':
- operand = mem[hexStr(reg['h']) + hexStr(reg['l'])]
- if operand in reg:
- operand = reg[operand]
- operand = negate(operand) + 1
- operated = borrow*flags['cy']*256 + reg[operated]
- add(operand,borrow,operated)
- flagUpdate('cy')
- flags['cy'] = int(not(flags['cy']))
- def bit(operation,rs):
- """Returns bitwise operation result of accumulator and register or data
- 'oper' can be:
- 0: bit-wise 'and'
- 1: bit-wise 'or'
- 2: bit-wise 'xor'"""
- global reg,flags
- # List of operations AND, OR, XOR in order
- operlist = [lambda x,y:x&y, lambda x,y:x|y, lambda x,y:x^y]
- if rs in reg:
- if rs == 'm': # ANA M, ORA M, XRA M
- rs = mem[hexStr(reg['h'])+hexStr(reg['l'])]
- bit(operation,rs)
- else: # ANA r, ORA r, XRA r
- reg['a'] = operlist[operation](reg['a'],reg[rs])
- else: # ANI, ORI, XRI
- reg['a'] = operlist[operation](reg['a'],rs)
- def shift(direction, num, fill):
- """Shifts 'num' in given 'direction' bit-wise after
- padding it with zeroes till 'fill' number of characters"""
- byte = binStr(num, fill)
- if direction == 'r':
- byte = byte[-1] + byte[:-1]
- elif direction == 'l':
- byte = byte[1:] + byte[0]
- return eval('0b' + byte)
- #============================= Executing function ==============================
- def execute(start):
- global mem,reg,flags,regPairs
- pc = counter(start) # initialize counter from 'start' address
- timeSlice, t = 15, time()
- def getAddr(startFrom):
- """Extract 4 byte address from address locations proceeding given
- 'startFrom' location in the memory, lsb then msb"""
- return (hexStr(mem[hexStr(startFrom.value() + 2, 4)]) +
- hexStr(mem[hexStr(startFrom.value() + 1, 4)]))
- while mem[pc()] != 0xcf :#and (time()-t <= timeSlice):
- instruction, op1, op2 = [opcode[mem[pc()]].group(i).lower() for i in [1,2,3]]
- print instruction, op1, op2
- if instruction == 'mov':
- move(op1,op2)
- elif instruction == 'mvi':
- pc.next()
- move(op1,mem[pc()])
- elif instruction == 'lxi':
- pc.next()
- move(regPairs[op1],mem[pc()])
- pc.next()
- move(op1,mem[pc()])
- elif instruction == 'ldax':
- addr = hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
- reg['a'] = mem[addr]
- elif instruction == 'stax':
- addr = hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
- mem[addr] = reg['a']
- elif instruction == 'lda':
- move('a', mem[getAddr(pc)])
- pc.next(2)
- elif instruction == 'sta':
- mem[getAddr(pc)] = reg['a']
- pc.next(2)
- elif instruction == 'lhld':
- reg['l'] = mem[getAddr(pc)]
- reg['h'] = mem[hexStr(eval(getAddr(pc)) + 1,4)]
- pc.next(2)
- elif instruction == 'shld':
- mem[getAddr(pc)] = reg['l']
- mem[hexStr(eval(getAddr(pc)) + 1,4)] = reg['h']
- elif instruction == 'xchg':
- reg['h'],reg['l'],reg['d'],reg['e'] = reg['d'],reg['e'],reg['h'],reg['l']
- elif instruction in ['add','adc']:
- add(op1, instruction=='adc')
- flagUpdate()
- elif instruction in ['adi','aci']:
- pc.next()
- add(mem[pc()],instruction=='aci')
- flagUpdate()
- elif instruction in ['sub','sbb']:
- sub(op1,instruction=='sbb')
- flagUpdate('szp')
- elif instruction in ['sui','sbi']:
- pc.next()
- sub(mem[pc()],instruction=='sbi')
- flagUpdate('szp')
- elif instruction == 'inr':
- add(1, 0, op1)
- carry = flags['cy']
- flagUpdate('szpcy',op1)
- flags['cy'] = carry
- elif instruction == 'dcr':
- add(0xff, 0, op1)
- carry = flags['cy']
- flagUpdate('szpcy',op1)
- flags['cy'] = carry
- elif instruction in ['inx','dcx']:
- pair = '0x' + hexStr(reg[op1]) + hexStr(reg[regPairs[op1]])
- pair = hexStr(eval(pair) + [1,-1][instruction=='dcx'])
- reg[op1],reg[regPairs[op1]] = eval('0x' + pair[:2]),eval('0x' + pair[2:])
- elif instruction == 'dad':
- reg['l'] += reg[regPairs[op1]]
- if reg['l'] >= 256:
- reg['l'] = eval('0b' + bin(reg['l'])[-8:])
- add(1,0,'h')
- flagUpdate('cy','h')
- reg['h'] += reg[op1]
- flagUpdate('cy','h')
- elif instruction == 'daa':
- if flags['ac'] or ((hexStr(reg['a']))[-1]).isalpha():
- add(6, 0)
- if flags['cy'] or ((hexStr(reg['a']))[0]).isalpha():
- add(0x60, 0)
- flagUpdate()
- elif instruction == 'jmp':
- pc.address = hexStr(eval('0x' + getAddr(pc)) - 1,4)
- elif 'j' in instruction:
- jump = [instruction==i for i in ['jz','jnz','jc','jnc','jpe','jpo','jm','jp']]
- conditions = [bool(flags['z']),not bool(flags['z']),bool(flags['cy']),not bool(flags['cy']),\
- bool(flags['p']),not bool(flags['p']),bool(flags['s']) ,not bool(flags['s'])]
- if conditions[jump.index(True)]:
- pc.address = hexStr(eval('0x' + getAddr(pc))-1, 4)
- else:
- pc.next(2)
- elif instruction == 'pchl':
- pc.address = hexStr(reg['h'], 2) + hexStr(reg['l'], 2)
- pc.address = hexStr(pc.value() - 1,4)
- elif instruction in ['ana','ani']:
- bit(0, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='ani']))
- flagUpdate('szp')
- flags['cy'], flags['ac'] = 0, 1
- elif instruction in ['ora','ori']:
- bit(1, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='ori']))
- flagUpdate('szp')
- flags['cy'], flags['ac'] = 0, 0
- elif instruction in ['xra','xri']:
- bit(2, ([op1,mem[hexStr(pc.value() + 1,4)]][instruction=='xri']))
- flagUpdate('szp')
- flags['cy'], flags['ac'] = 0, 0
- elif instruction == 'cmp':
- if op1 == 'm':
- m = mem[hexStr(reg['h'])+hexStr(reg['l'])]
- flags['cy'] = int(reg['a'] < m)
- flags['z'] = int(reg['a'] == m)
- else:
- flags['cy'] = int(reg['a'] < reg[op1])
- flags['z'] = int(reg['a'] == reg[op1])
- elif instruction == 'cpi':
- op1 = mem[hexStr(pc.value() + 1, 4)]
- flags['cy'] = int(reg['a'] < op1)
- flags['z'] = int(reg['a'] == op1)
- elif instruction == 'rlc':
- reg['a'] = shift('l', reg['a'], 8)
- flags['cy'] = binStr(reg['a'])[-1]
- elif instruction == 'rrc':
- reg['a'] = shift('r', reg['a'], 8)
- flags['cy'] = binStr(reg['a'])[0]
- elif instruction == 'ral':
- reg['a'] = shift('l', reg['a'], 8)
- carry, flags['cy'] = flags['cy'], int(binStr(reg['a'])[-1])
- reg['a'] = eval('0b' + binStr(reg['a'])[:-1] + str(carry))
- elif instruction == 'rar':
- reg['a'] = shift('r', reg['a'], 8)
- carry, flags['cy'] = flags['cy'], int(binStr(reg['a'])[0])
- reg['a'] = eval('0b' + str(carry) + binStr(reg['a'])[1:])
- elif instruction == 'cma':
- reg['a'] = negate(reg['a'])
- elif instruction == 'cmc':
- flags['cy'] = int(not flags['cy'])
- elif instruction == 'stc':
- flags['cy'] = 1
- pc.next()
- #-------------------------------------------------------------------------------
- #============================= Interface Functions =============================
- def drawButtons():
- global buttons, buttonFrame
- numPadText = ['C\nU1','D\nU2','E\nU3','F\nU4',\
- '8\nGo/H','9\nL','A\nLOAD','B\nSAVE',\
- '4\nSPH','5\nSPL','6\nPCH','7\nPCL',\
- '0\nSET','1\nCODE','2\nSTEP','3\nREG']
- opPadText = "VI,DCR,EXEC,INR".split(',')
- gap = 50
- startX, startY = 350, 0
- width, height = 100, 100
- for i in range(4):
- buttons.append(Button(buttonFrame, opPadText[i],
- startX - width - gap,
- startY + (height*i),
- width, height, buttonPress))
- for i in range(4):
- for j in range(4):
- buttons.append(Button(buttonFrame, numPadText[4*i+j],
- startX + (width*j),
- startY + (height*i),
- width, height, buttonPress))
- buttons.append(Button(buttonFrame, "RST",
- startX - (width*2) - gap, startY,
- width-2, height-2, buttonPress))
- def update(add=None):
- global addressLED, contentLED, address, content, mem
- if not add:
- for i in range(4):
- addressLED[i].colorSeg(address[len(address)-4+i])
- for i in range(2):
- contentLED[i].colorSeg(content[len(content)-2+i])
- else:
- if mem.has_key(add):
- content = hexStr(mem[add])
- else:
- content, mem[add] = '00', 0
- update()
- def buttonPress(key):
- global address, content, activeField, mode, mem
- # print "You pressed {}\nMode: {}\nActive:{}".format(key, mode, activeField)
- if len(key) < 2 and ('0' <= key <= 'f'): # pressed key is a digt/numpad key
- if mode == "reset":
- # if 'reset' mode then keys have special meaning
- # denoted by text blow the numbers on the keys
- if key == "0": # '0' means 'SET' instruction
- activeField = "address"
- #firstEntry = True # the first entry would blank the address
- address, content = ' '*4, ' '*2
- mode = "entry"
- elif key == "3": # '3' means 'REG' instruction
- mode = "reg"
- activeField = "address"
- address, content = ' '*4, ' '*2
- update()
- elif key == "8": # '8' means 'GO' instruction
- address, content = ' '*4, ' '*2
- mode = "go"
- activeField = "address"
- elif key == "b": # 'B' means 'SAVE' instruction
- root.iconify()
- root.update()
- fname = raw_input("Enter the name of the file to be saved as\n")
- f = open(os.path.join(os.getcwd(), 'bin\\{}'.format(fname) + '.pkl'), 'w')
- pickle.dump(mem, f)
- print "Saved successfully"
- f.close()
- root.deiconify()
- elif key == "a": # 'A' means 'LOAD' instruction
- root.iconify()
- root.update()
- fname = raw_input("Enter the name of the file to be loaded\n")
- try:
- f = open(os.path.join(os.getcwd(), 'bin\\{}'.format(fname) + '.pkl'), 'r')
- except IOError:
- print "Sorry, required file could not be located"
- else:
- mem = pickle.load(f)
- print "Loaded successfully"
- f.close()
- root.deiconify()
- update()
- elif mode in ["entry","go"]:
- # if 'entry' mode, the numbers are appended to
- # the respective field denoted by activeField variable
- if activeField == "content":
- content = (content + key)[1:] # append key to current value
- elif activeField == "address":
- address = (address + key)[1:] # append key to current value
- update()
- elif mode == "reg":
- if key == "rst":
- mode = "reset"
- address, content = 'frie', 'nd'
- activeField = ""
- elif activeField == "address":
- if key in 'abcde':
- address = ' '*3 + key
- content = hexStr(reg[key], 2)
- elif key == "8":
- address = ' '*3 + 'h'
- content = hexStr(reg['h'], 2)
- elif key == '9':
- address = ' '*3 + 'l'
- content = hexStr(reg['l'], 2)
- elif key == 'f':
- address = ' '*3 + 'f'
- content = hexStr(eval('0b' + ''.join([str(flags[char]) for char
- in 's,z,-,ac,-,p,-,cy'.split(',')])), 2)
- activeField = "content"
- elif activeField == "content" and address[-1] != 'f':
- content = (content + key)[1:]
- update()
- elif key in ["inr","dcr"]: # pressed 'INR' key
- diff = 1 if key == "inr" else -1
- if activeField == "address":
- activeField = "content"
- update(address)
- elif activeField == "content":
- if mode == "reg":
- reg[address[-1]] = int(content,16)
- activeField ="address"
- buttonPress('abcde89f'[('abcdehlf'.index(address[-1]) + diff)%8])
- else:
- try:
- mem[address] = int(content, 16)
- except ValueError:
- address, content = 'ferr', 'or'
- update()
- else:
- address = hexStr(int(address,16) + diff, 4)
- update(address)
- elif key == 'rst': # pressed 'RST' key
- address, content = "frie", "nd"
- mode = "reset"
- update()
- elif key == "exec":
- if mode == "go":
- activeField = ""
- pc = address
- #print "Executing from {}".format(pc)
- address = ' e'
- update()
- root.update()
- t = time()
- try:
- execute(pc)
- except:
- address, content = 'ferr', 'or'
- update()
- print "\nUnexpected Error: ", sys.exc_info()
- else:
- print "Time taken: {}".format(time()-t)
- buttonPress('rst')
- #execute(pc)
- #-------------------------------------------------------------------------------
- #=============================== User Interface ================================
- root = Tk()
- root.title('8085 Microprocessor simulator')
- screenHeight, screenWidth = root.winfo_screenheight(), root.winfo_screenwidth()
- windowHeight, windowWidth = int(screenHeight*(5/6.0)), int(screenWidth*(2/3.0))
- windowPadX, windowPadY = int(screenWidth*(1/6.0)), int(screenHeight*(1/24.0))
- root.geometry('{}x{}+{}+{}'.format(windowWidth, windowHeight, windowPadX, windowPadY))
- root.pack_propagate(False)
- root.config(background = 'black')
- #----------------------------------Key Bindings---------------------------------
- def f(e):
- char = e.char
- if char == '+':
- buttonPress('inr')
- elif char == '-':
- buttonPress('dcr')
- else:
- buttonPress(e.char.lower())
- for char in '0123456789+-abcdefABCDEF':
- root.bind(char, f)
- root.bind('<space>', lambda e:buttonPress('rst'))
- root.bind('<Return>', lambda e:buttonPress('exec'))
- #-------------------------------------------------------------------------------
- displayFrame = Frame(root, background = 'black', height=200)
- displayFrame.pack(side=TOP, fill=X)
- buttonFrame = Frame(root, background = 'black')
- buttonFrame.pack(side=TOP, fill=BOTH, expand=1)
- addressLED = [LED(displayFrame, str(i), 75*i + 200, 25, 75, 150) for i in range(4)]
- contentLED = [LED(displayFrame, str(i), 75*i + (200+75*4+25), 25, 75, 150) for i in range(2)]
- address = ""
- content = ""
- activeField = ""
- firstEntry = False
- mode = 'reset'
- buttons = []
- #-------------------------------------------------------------------------------
- #============================ Functionality Checks =============================
- address = "frie"
- content = "nd"
- update()
- def main():
- drawButtons()
- root.mainloop()
- if __name__ == '__main__':
- main()
- #-------------------------------------------------------------------------------
- # Todo3 Assembler
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement