#!/usr/bin/python from mipsasm import * def NEXT(): # s0 plays the role of %esi in the Jones system # s1 plays the role of %eax in the Jones system lw(s1,0,s0) addi(s0,s0,4) lw(s1,0,s1) jr(s1) def store(reg, label): la(t7, label) sw(reg, 0, t7) # Also following Jones we use sp for the parameter stack # and fp for the return stack # Macros to deal with the return stack def PUSHRSP(reg): addi(fp, fp, -4) sw(reg, 0, fp) def POPRSP(reg): lw(reg, 0, fp) addi(fp, fp, 4) link = '0x0' F_IMMED=0x80 F_HIDDEN=0x20 F_LENMASK=0x1f def defword(wordname, lbl=None, flags=0): global link if lbl==None: lbl = wordname asm('.data') asm('.align 2') label('name_'+lbl) asm('.word ' + link) link = 'name_'+lbl asm('.byte ' + ('0x%x' % (len(wordname)+flags))) asm('.ascii "' + wordname + '"') asm('.align 2') label(lbl) asm('.word DOCOL') # each use of defword is followed by a list of forth word pointers def defcode(wordname, lbl=None, flags=0): global link if lbl==None: lbl = wordname asm('.data') asm('.align 2') label('name_'+lbl) asm('.word ' + link) link = 'name_'+lbl asm('.byte ' + ('0x%x' % (len(wordname)+flags))) asm('.ascii "' + wordname + '"') asm('.align 2') label(lbl) asm('.word code_'+lbl) asm('.text') #asm('.align 2') -- should be true already label('code_'+lbl) # each use of defcode is followed by assembly code def forth(): # GROUP 1 # GROUP 2 #Pops the top element off the stack defcode("DROP") addi(sp, sp, 4) NEXT() #swaps the top two elements of the stack defcode ("SWAP") lw (t0, 0, sp) lw (t1, 4, sp) sw (t0, 4, sp) sw (t1, 0, sp) NEXT() #duplicates the top element of the stack defcode ("DUP") lw(t0, 0, sp) addi(sp, sp, -4) sw(t0, 0, sp) NEXT() #Basically does the same thing as swap -- gets the second element and saves it #on the top of the stack defcode ("OVER") lw (t0, 0, sp) lw (t1, 4, sp) sw (t0, 4, sp) sw (t1, 0, sp) NEXT() #Does the same as swap #Rotates the top three elements defcode ("ROT") lw (t0, 0, sp) lw (t1, 4, sp) lw (t2, 8, sp) sw (t0, 8, sp) sw (t2, 4, sp) sw (t1, 0, sp) NEXT() #Another version of the ROT command -- saves the elements in a different order defcode ("-ROT", "NROT") lw (t0, 0, sp) lw (t1, 4, sp) lw (t2, 8, sp) sw (t1, 8, sp) sw (t0, 4, sp) sw (t2, 0, sp) NEXT() #Removes the top 2 elements on the stack defcode ("2DROP", "TWODROP") addi(sp, sp, 8) NEXT() #Duplicates the top two elements on the stack defcode ("2DUP", "TWODUP") lw(t0, 0, sp) lw(t1, 4, sp) addi(sp, sp, -8) sw(t1, 4, sp) sw(t0, 0, sp) NEXT() #Swaps the top 2 elements with the 2 right after them on the stack #also swaps the pairs with each other defcode ("2SWAP", "TWOSWAP") lw (t0, 0, sp) lw (t1, 4, sp) lw (t2, 8, sp) lw (t3, 12, sp) sw (t1, 12, sp) sw (t0, 8, sp) sw (t3, 4, sp) sw (t2, 0, sp) NEXT() #Duplicates the top of the stack if it isn't equal to zero defcode ("?DUP", "QDUP") lw(t0, 0, sp) beqz (t0, "qdupout") addi (sp, sp, -4) sw (t0, 0, sp) label("qdupout") NEXT() #adds 1 to the top of the stack defcode ("1+", "INCR") lw (t0, 0, sp) addi (t0, t0, 1) sw (t0, 0, sp) NEXT() #subtracts 1 from the top of the stack defcode ("1-", "DECR") lw (t0, 0, sp) sub (t0, t0, 1) sw (t0, 0, sp) NEXT() #Adds 4 to the top of the stack defcode ("4+", "INCR4") lw (t0, 0, sp) addi (t0, t0, 4) sw (t0, 0, sp) NEXT() #subtracts 4 from the top of the stack defcode ("4-", "DECR4") lw (t0, 0, sp) sub (t0, t0, 4) lw (t0, 0, sp) NEXT() #Adds the top element of the stack to the next element in the stack defcode ("+", "ADD") lw (t0, 0, sp) lw (t1, 4, sp) add (t1, t1, t0) addi (sp, sp, -4) sw (t1, 0, sp) NEXT() #subtracts the top element of the stack from the second element in the stack defcode ("-", "SUB") lw (t0, 0, sp) lw (t1, 4, sp) sub (t1, t1, t0) addi (sp, sp, -4) sw (t1, 0, sp) NEXT() #multiplies the second element of the stack by the defcode ("*", "MUL") lw (t0, 0, sp) lw (t1, 4, sp) mul (t1, t1, t0) addi (sp, sp, -4) sw (t0, 0, sp) NEXT() #DIVMOD -- divides the top two elements of the stack saves the defcode ("/MOD", "DIVMOD") lw (t0, 0, sp) lw (t1, 4, sp) beqz (t1, "modout") div(t0, t1) # sw (MFLOW, 4, sp) not right - ch # sw (MFHIGH, 0, sp) not right - ch mflo(t0) sw(t0, 4, sp) # added - ch mfhi(t0) sw(t0, 0, sp) # added - ch label("modout") NEXT() # GROUP 3 TRUE = genLabel("TRUE") FALSE = genLabel("FALSE") defcode("=","EQU") # Top two words are equal lw(s1, 0, sp) # pop to $eax addi(sp, sp, 4) lw(s2, 0, sp) # pop to $ebx addi(sp, sp, 4) beq(s1,s2,TRUE) bne(s1,s2,FALSE) defcode("<>","NEQU") # Top two words are not equal lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) bne(s1, s2, TRUE) beq(s1, s2, FALSE) defcode("<","LT") # s1 is less than s2 lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) blt(s1, s2, TRUE) bge(s1, s2, FALSE) defcode(">","GT") # s1 is greater than s2 lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) bgt(s1, s2, TRUE) ble(s1, s2, FALSE) defcode("<=","LE") # s1 is less than or equal to s2 lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) ble(s1, s2, TRUE) bgt(s1, s2, FALSE) defcode(">=","GE") # s1 is greater than or equal to s2 lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) bge(s1, s2, TRUE) blt(s1, s2, FALSE) defcode("0=","ZEQU") # s1 is equal to 0 lw(s1, 0, sp) addi(sp, sp, 4) beqz(s1, TRUE) bnez(s1, FALSE) # broken defcode("0<>","ZNEQU") # s1 is not equal to 0 lw(s1, 0, sp) addi(sp, sp, 4) bnez(s1, TRUE) # broken beqz(s1, FALSE) defcode("0<","ZLT") # s1 is less than 0 lw(s1, 0, sp) addi(sp, sp, 4) bltz(s1, TRUE) bgez(s1, FALSE) defcode("0>","ZGT") # s1 is greater than 0 lw(s1, 0, sp) addi(sp, sp, 4) bgtz(s1, TRUE) blez(s1, FALSE) defcode("0<=","ZLE") # s1 is less than or equal to 0 lw(s1, 0, sp) addi(sp, sp, 4) blez(s1, TRUE) bgtz(s1, FALSE) defcode("0>=","ZGE") # s1 is greater than or equal to 0 lw(s1, 0, sp) addi(sp, sp, 4) bgez(s1,TRUE) bltz(s1,FALSE) # TRUE label label(TRUE) # added - ch sub(s1, s1, s1) add(s1, s1, 1) addi(sp, sp, -4) # push $eax sw(s1, 0, sp) NEXT() # FALSE label label(FALSE) # added - ch sub(s1,s1,s1) addi(sp, sp, -4) # push $eax sw(s1, 0, sp) NEXT() defcode("AND") # bitwise AND lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) and_(s3,s1,s2) addi(sp, sp, -4) sw(s3, 0, sp) NEXT() defcode("OR") # bitwise OR lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) or_(s3,s1,s2) addi(sp, sp, -4) sw(s3, 0, sp) NEXT() defcode("XOR") # bitwise exclusive OR lw(s1, 0, sp) addi(sp, sp, 4) lw(s2, 0, sp) addi(sp, sp, 4) xor_(s3,s1,s2) addi(sp, sp, -4) sw(s3, 0, sp) NEXT() defcode("INVERT") # bitwise NOT lw(s1, 0, sp) addi(sp, sp, 4) nor_(s3,s1,s1) addi(sp, sp, -4) sw(s3, 0, sp) NEXT() # GROUP 4 defcode("EXIT", "EXIT") POPRSP(s0) NEXT() defcode("LIT", "LIT") lw(s1,0,s0) # lodsl addi(s0,s0,4) addi(sp, sp, -4) # push %eax sw(s1, 0, sp) NEXT() # GROUP 5 defcode('CCOPY') lw(t0,4,sp) lb(t1,0,t0) lw(t2,0,sp) addi(sp,sp,4) sb(t1,0,t2) addi(t2,t2,1) addi(sp,t0,1) addi(sp,sp,-4) # changed from addiu by ch sw(t2,0,sp) NEXT() defcode('STORE') lw (t0,0,sp) lw(t1,4,sp) sw(t0,0,t1) addi(sp,sp,8) NEXT() defcode('FETCH') lw(t0,0,sp) lw(t1,0,t0) sw(t1,0,sp) NEXT() defcode('ADDSTORE') lw(t0,0,sp) #address to store at lw(t1,4,sp) #amount to add lw(t2,0,t0) #get the value at t0 add(t2,t2,t1) #add em sw(t2,0,t0) #store it to the address addi(sp,sp,8) #fix the stack NEXT() defcode('SUBSTORE') lw(t0,4,sp) #address to store at lw(t1,0,sp) #amount to add lw(t2,0,t0) #get the value at t0 sub(t2,t2,t1) #add em sw(t2,0,t0) #store it to the address addi(sp,sp,8) #fix the stack NEXT() defcode('STOREBYTE') lb(t0,0,sp) lb(t1,4,sp) sb(t0,0,t1) addi(sp,sp,8) NEXT() defcode('FETCHBYTE') lb(t0,0,sp) lb(t1,0,t0) sb(t1,0,sp) NEXT() defcode('CMOVE') lw(t0,0,sp) #pop the count lb(t1,4,sp)#pop string destination lb(t2,8,sp)#pop string source address addi(sp,sp,12) asm('loop:') done = genLabel("done") bgez(t0,done) move(t1,t2) addi(t1,t1,1)#next byte addi(t2,t2,1)#add one to get the next byte j('loop') label(done) NEXT() # GROUP 6 defcode(">R","TOR") lw(s1,0,sp) addi(sp, sp, 4) PUSHRSP(s1) NEXT() defcode("R>","FROMR") POPRSP(s1) addi(sp, sp, -4) sw(s1, 0, sp) NEXT() defcode("RSP@","RSPFETCH") addi(sp, sp, -4) sw(fp, 0, sp) NEXT() defcode("RSP!","RSPSTORE") lw(fp, 0, sp) addi(sp, sp, 4) NEXT() defcode("RDROP","RDROP") addi(fp,fp,4) NEXT() defcode("DSP@","DSPFETCH") add(s1,sp,zero) addi(sp, sp, -4) sw(s1, 0, sp) NEXT() defcode("DSP!","DSPSTORE") lw(fp, 0, sp) addi(sp, sp, 4) NEXT() forth() def group1(): defcode("WORD") jal("_WORD") sw(s3, 0, sp) sw(t2, 0, sp) NEXT() label("_WORD") # lw(s0, "\\") # lw(s1, " ") # lw(s2, "\n") # lw(s4, "-") label("1_word") jal("_KEY") #this assumes that call _KEY puts the current keystroke in $a0 beq(a0, s0, "3_word") beq(a0, s1, "1_word") move("word_buffer", s3) label("2_word") sb(a0, 0, s3) jal("_KEY") beq(a0, s1, "2_word") # sub("word_buffer", s3) move(s3, t2) move("word_buffer", s3) jr(ra) label("3_word") jal("_KEY") beq(a0, s2, "1_word") bne(a0, s2, "3_word") asm(".data") label("word_buffer") asm(".space 32") defcode("NUMBER") lw(t2, 0, sp) lw(s3, 0, sp) jal("_NUMBER") sw(t0, 0, sp) sw(t2, 0, sp) NEXT() label("_NUMBER") xor_(t0, t0, t0) xor_(t1, t1, t1) beqz(t2, "5_NUMBER") move("var_BASE", t3) move(s3, t1) addi (s3, s3, 1) sw(t0, 0, sp) # bnez(s4, t1, "2_NUMBER") # bnez takes only 2 arguments lw(t0, 0, sp) sw(t1, 0, sp) addi(t2, t2, -1) # bnez(t2, t2, "1_NUMBER") lw(t1, 0, sp) move("1", t2) jr("ra") label("1_NUMBER") mult(t3, t1) mflo(t1) move(s3, t1) addi(s3, s3, 1) # lable("2_NUMBER") bltz(t1, "4_NUMBER") # lw(10, s7) bgt(t1, s7, "3_NUMBER") # lw(17, s7) bgt(t1, s7, "4_NUMBER") addi(t1, t1, 10) label("3_NUMBER") bge(t3, t1, "4_NUMBER") add(t1, t0, t0) addi(t2, t2, -1) # bgtz(t2, t2, "1_NUMBER") # one argument label("4_NUMBER") lw(t1, 0, sp) beqz(t1, "5_NUMBER") neg(t0, t0) label("5_NUMBER") jr(ra) #">CFA" and ">DFA" def group2(): # Missing FIND defcode (">CFA", "TCFA") lw (t0, 0, sp) addi (t0, t0, 4) move (t0, t1) addi (t0, t0, 1) # and_(t2, t1) # needs three args li (t3, 0) # add (t3, t0) # three args addi (t0, t0, 4) sw (t0, 0, sp) NEXT() defcode (">DFA", "TDFA") # why not use the style given in Jones' paper? lw (t0, 0, sp) addi (t0, t0, 4) move (t0, t1) addi (t0, t0, 1) # and_(t2, t1) li (t3, 0) # add (t3, t0) addi (t0, t0, 8) sw (t0, 0, sp) NEXT() def group3(): # Create defcode("CREATE", "CREATE") # Get the name length and address. lw(s3, 0, sp) # pop length to $ecx addi(sp, sp, 4) lw(s2, 0, sp) # pop address of name to %ebx addi(sp, sp, 4) # Link pointer. # la(s4, var_HERE) # move address of header to %edi # undefined python variables # la(t7, var_LATEST) lw(s1, 0, t7) # get link pointer, store in %eax addi(s4, s4, -4) sw(s1, 0, s4) # store link pointer in the header # Length byte and the word itself addi(s4, s4, -4) sw(s3, 0, s4) # store Length in the header addi(sp, sp, -4) sw(s0, 0, sp) # push %esi, save value move(s0, s2) # move %ebx to %esi addi(s4, s4, -4) sw(s0, 0, s4) # store Name lw(s0, 0, sp) # pop %esi, get old value back addi(sp, sp, 4) # Update LATEST and HERE # la(t7, var_HERE) lw(s1, 0, t7) # move address of header to %eax # store(s1, var_LATEST) # update var_LATEST # store(s4, var_HERE) # update var_HERE NEXT() # COMMA _COMMA = genLabel("_COMMA") # defcode(",",COMMA) # undefined python variable lw(s1, 0, sp) # pop to %eax addi(sp, sp, 4) jal(_COMMA) NEXT() # _COMMA label label(_COMMA) # la(s4, var_HERE) addi(s4, s4, -4) sw(s1, 0, s4) # store(s4, var_HERE) jr(ra) # Left Bracket defcode("[", "LBRAC", F_IMMED) xor_(s1, s1, s1) # store(s1, var_STATE) NEXT() # Right Bracket defcode("]", "RBRAC") move(s1, 1) # store(s1, var_STATE) NEXT() # isn't the assembler directive .word for MIPS? # COLON defword(":", "COLON") asm('.int WORD') asm('.int CREATE') asm('.int LIT, DOCOL, COMMA') asm('.int LATEST, FETCH, HIDDEN') asm('.int RBRAC') asm('.int EXIT') # SEMICOLON defword(";", "SEMICOLON", F_IMMED) asm('.int LIT, EXIT, COMMA') asm('.int LATEST, FETCH, HIDDEN') asm('.int LBRAC') asm('.int EXIT') def group4(): asm('.data') asm('.align 2') buffer = genLabel("buffer") label(buffer) asm('.space 4096') currkey = genLabel("currkey") label(currkey) asm('.word ' + buffer) asm('.text') defcode("KEY") read = genLabel("read") exit = genLabel("exit") addi(sp, sp, -4) # allocate one space on the stack sw(ra, 0, sp) # store the return address jal('_KEY') # call KEY lw(ra, 0, sp) # restore the return address sw(s1, 0, sp) # push eax onto the stack NEXT() label('_KEY') la(t1, currkey) lw(t0, 0, t1) # load the current position lbu(s1, 0, t0) # load the next char beqz(s1, read) # read more if no more chars li(t1, 4) beq(s1, t1, exit) # exit on ^D addi(t0, t0, 1) # increment the current position sw(t0, 0, t1) # store the current position jr(ra) # return label(read) li(v0, 8) # prepare to read a string la(a0, buffer) # load the address of the buffer sw(a0, 0, t1) # move the current position to the start of the buffer li(a1, 4096) # load the buffer size syscall() # read input b('_KEY') # go back to KEY label(exit) li(v0, 10) # prepare to exit syscall() # exit asm('.data') asm('.align 2') char = genLabel("char") label(char) asm('.space 2') # 1 for the char, 1 for a null terminator asm('.text') defcode("EMIT") lw(s1, 0, sp) # take one char off the stack sw(ra, 0, sp) # store the return address jal('_EMIT') # call to EMIT lw(ra, 0, sp) # restore the return address addi(sp, sp, 4) # free one space on the stack NEXT() label('_EMIT') li(v0, 4) # set up a print call la(a0, char) # load the address of the char space sw(s1, 0, a0) # store the new char syscall() # print the new char jr(ra) # return def group5(): defcode('IMMEDIATE') # move(t0, LATEST) # t0 is edi #undefined python var addi(t0, t0, 4) lb(t1, 0, t0) # xor(F_IMMED, t1) # toggle immed bit # undefined xor sb(t1, 0, t0) NEXT() defcode('HIDDEN') lw(t0, 0, sp) addi(sp, sp, 4) addi(t0, t0, 4) lb(t1, 0, t0) # xor(F_HIDDEN, t1) # toggle hidden bit sb(t1, 0, t0) NEXT() defcode('TICK') lw(t0, 0, t1) # t0 is eax t1 is esi addi(sp, sp, -4) sw(t0, 0, sp) NEXT() defcode("HIDE") asm(".word WORD") asm(".word FIND") asm(".word HIDDEN") asm(".word EXIT") #Group 6 #Branching def group6(): defcode("BRANCH","BRANCH") asm('branch:') lw(t0, 0, sp) addi(sp, sp, -4) addi(fp,fp,t0) NEXT() defcode("0BRANCH", "ZBRANCH") lw(t0, 0, sp) addi(sp, sp, -4) if t0==0: j('branch') NEXT() # Group 6: please also code up LITSTRING, TELL, CHAR, and EXECUTE group1() group2() group3() group4() group5() group6()