├── .gitignore ├── asm_toy_2 ├── asm_03.s ├── asm_00.s ├── asm_02.s ├── asm_01.s ├── test.s ├── README.rst ├── asm_04.s └── interp_asm.py ├── asm_toy_1 ├── asm_00.s ├── README.rst └── simple_asm.py ├── parc_interpreter ├── conftest.py ├── README.rst ├── interp_asm_test.py └── interp_asm_jit.py ├── bf ├── README.rst ├── tutorial_bf_jit.py ├── tutorial_bf_jit_opt.py ├── tutorial_bf.py └── tutorial_99.b └── README.rst /.gitignore: -------------------------------------------------------------------------------- 1 | *__pycache__ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /asm_toy_2/asm_03.s: -------------------------------------------------------------------------------- 1 | mfc0 r1, mngr2proc < 5 2 | addiu r3, r1, 0x0004 3 | mtc0 r3, proc2mngr > 10 4 | -------------------------------------------------------------------------------- /asm_toy_1/asm_00.s: -------------------------------------------------------------------------------- 1 | addiu r1, r0, 0x1 2 | addiu r2, r0, 0x2 3 | addu r3, r1, r2 4 | print a, b, r3 5 | -------------------------------------------------------------------------------- /asm_toy_2/asm_00.s: -------------------------------------------------------------------------------- 1 | addiu r1, r0, 0x1 2 | addiu r2, r0, 0x2 3 | addu r3, r1, r2 4 | print a, b, r3 5 | -------------------------------------------------------------------------------- /asm_toy_2/asm_02.s: -------------------------------------------------------------------------------- 1 | mfc0 r20, mngr2proc < 5 2 | addiu r21, r20, 0x0004 3 | mtc0 r21, proc2mngr > 9 4 | -------------------------------------------------------------------------------- /asm_toy_2/asm_01.s: -------------------------------------------------------------------------------- 1 | # A comment 2 | addiu r1, r0, 0x1 3 | addiu r2, r0, 0x2 4 | # Another comment 5 | addu r3, r1, r2 6 | print r3 7 | -------------------------------------------------------------------------------- /parc_interpreter/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | def pytest_addoption(parser): 4 | parser.addoption( "--cpython", action="store_true", 5 | help="use cpython" ) 6 | 7 | -------------------------------------------------------------------------------- /asm_toy_2/test.s: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Move src value into register 4 | mfc0 r1, mngr2proc < 4278255360 5 | 6 | 7 | # Instruction under test 8 | xori r3, r1, 3855 9 | 10 | 11 | # Check the result 12 | mtc0 r3, proc2mngr > 4278251535 13 | 14 | 15 | 16 | # Move src value into register 17 | mfc0 r1, mngr2proc < 267390960 18 | 19 | 20 | # Instruction under test 21 | xori r3, r1, 61680 22 | 23 | 24 | # Check the result 25 | mtc0 r3, proc2mngr > 267452160 26 | 27 | 28 | 29 | # Move src value into register 30 | mfc0 r1, mngr2proc < 16711935 31 | 32 | 33 | # Instruction under test 34 | xori r3, r1, 3855 35 | 36 | 37 | # Check the result 38 | mtc0 r3, proc2mngr > 16715760 39 | 40 | 41 | 42 | # Move src value into register 43 | mfc0 r1, mngr2proc < 4027576335 44 | 45 | 46 | # Instruction under test 47 | xori r3, r1, 61680 48 | 49 | 50 | # Check the result 51 | mtc0 r3, proc2mngr > 4027515135 52 | 53 | 54 | -------------------------------------------------------------------------------- /asm_toy_2/README.rst: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | README: Toy Interpreter for Assembly 2 3 | ======================================================================== 4 | 5 | This interpreter is a similar to the asm_toy_1, but includes mtc0 and 6 | mfc0 instructions for testing, as well as demonstrates how a register 7 | map can be used to simplify the interpreter design. 8 | 9 | ------------------------------------------------------------------------ 10 | Quick Start 11 | ------------------------------------------------------------------------ 12 | 13 | Running the simple interpreter in CPython:: 14 | 15 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' \ 16 | python interp_asm.py asm_04.s 17 | 18 | Using RPython to create an interpreter with no JIT:: 19 | 20 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 21 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 22 | interp_asm.py 23 | $ ./interp_asm-c asm_04.s 24 | 25 | -------------------------------------------------------------------------------- /asm_toy_1/README.rst: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | README: Toy Interpreter for Assembly 2 3 | ======================================================================== 4 | 5 | This interpreter is a very basic foundation for an ISA interpreter, it 6 | only includes addiu, addu, and print instructions. It is useful seeing 7 | the minimal code needed to make a simple ISA interpreting simulator. 8 | 9 | ------------------------------------------------------------------------ 10 | Quick Start 11 | ------------------------------------------------------------------------ 12 | 13 | Running the simple interpreter in CPython:: 14 | 15 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' \ 16 | python simple_asm.py asm_00.s 17 | 18 | Using RPython to create an interpreter with no JIT:: 19 | 20 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 21 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 22 | simple_asm.py 23 | $ ./simple_asm-c asm_00.s 24 | 25 | -------------------------------------------------------------------------------- /parc_interpreter/README.rst: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | README: PARC ISA Interpreter 3 | ======================================================================== 4 | 5 | This interpreter is a full interpreter for the PARC ISA! Note that as 6 | an interpreter it expects assembly files, **not** binaries! 7 | 8 | ------------------------------------------------------------------------ 9 | Testing the Interpreter 10 | ------------------------------------------------------------------------ 11 | 12 | Included is a test runner script which can run a full array of PARC 13 | assembly tests. It requires that both PyMTL and the py.test Python 14 | package is installed on the local system. To run the assembly tests with 15 | CPython:: 16 | 17 | $ cd parc_interpreter 18 | $ py.test interp_asm_test.py --verbose --cpython 19 | 20 | Before running the assembly tests with RPython, first compile the C 21 | implmementation. 22 | 23 | The C implementation **without** JIT (should take ~30 seconds):: 24 | 25 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 26 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 27 | interp_asm_jit.py 28 | 29 | The C implementation **with** JIT (should take ~500 seconds):: 30 | 31 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 32 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 33 | --opt=jit \ 34 | interp_asm_jit.py 35 | 36 | The run the tests:: 37 | 38 | $ py.test interp_asm_test.py --verbose 39 | 40 | The the interpreter on an assembly file directly:: 41 | 42 | $ ./interp_asm_jit-c test.s 43 | 44 | -------------------------------------------------------------------------------- /asm_toy_2/asm_04.s: -------------------------------------------------------------------------------- 1 | mfc0 r1, mngr2proc < 1 2 | mfc0 r2, mngr2proc < 2 3 | mfc0 r3, mngr2proc < 3 4 | mfc0 r4, mngr2proc < 4 5 | mfc0 r5, mngr2proc < 5 6 | mfc0 r6, mngr2proc < 6 7 | mfc0 r7, mngr2proc < 7 8 | mfc0 r8, mngr2proc < 8 9 | mfc0 r9, mngr2proc < 9 10 | mfc0 r10, mngr2proc < 10 11 | mfc0 r11, mngr2proc < 11 12 | mfc0 r12, mngr2proc < 12 13 | mfc0 r13, mngr2proc < 13 14 | mfc0 r14, mngr2proc < 14 15 | mfc0 r15, mngr2proc < 15 16 | mfc0 r16, mngr2proc < 16 17 | mfc0 r17, mngr2proc < 17 18 | mfc0 r18, mngr2proc < 18 19 | mfc0 r19, mngr2proc < 19 20 | mfc0 r20, mngr2proc < 20 21 | addiu r1, r1, 0x0004 22 | addiu r2, r2, 0x0004 23 | addiu r3, r3, 0x0004 24 | addiu r4, r4, 0x0004 25 | addiu r5, r5, 0x0004 26 | addiu r6, r6, 0x0004 27 | addiu r7, r7, 0x0004 28 | addiu r8, r8, 0x0004 29 | addiu r9, r9, 0x0004 30 | addiu r10, r10, 0x0004 31 | addiu r11, r11, 0x0004 32 | addiu r12, r12, 0x0004 33 | addiu r13, r13, 0x0004 34 | addiu r14, r14, 0x0004 35 | addiu r15, r15, 0x0004 36 | addiu r16, r16, 0x0004 37 | addiu r17, r17, 0x0004 38 | addiu r18, r18, 0x0004 39 | addiu r19, r19, 0x0004 40 | addiu r20, r20, 0x0004 41 | mtc0 r1, proc2mngr > 5 42 | mtc0 r2, proc2mngr > 6 43 | mtc0 r3, proc2mngr > 7 44 | mtc0 r4, proc2mngr > 8 45 | mtc0 r5, proc2mngr > 9 46 | mtc0 r6, proc2mngr > 10 47 | mtc0 r7, proc2mngr > 11 48 | mtc0 r8, proc2mngr > 12 49 | mtc0 r9, proc2mngr > 13 50 | mtc0 r10, proc2mngr > 14 51 | mtc0 r11, proc2mngr > 15 52 | mtc0 r12, proc2mngr > 16 53 | mtc0 r13, proc2mngr > 17 54 | mtc0 r14, proc2mngr > 18 55 | mtc0 r15, proc2mngr > 19 56 | mtc0 r16, proc2mngr > 20 57 | mtc0 r17, proc2mngr > 21 58 | mtc0 r18, proc2mngr > 22 59 | mtc0 r19, proc2mngr > 23 60 | mtc0 r20, proc2mngr > 24 61 | -------------------------------------------------------------------------------- /bf/README.rst: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | README: BF Interpreter 3 | ======================================================================== 4 | 5 | BF is a very simple interpreter for the brainf*ck language. 6 | 7 | ------------------------------------------------------------------------ 8 | Quick Start 9 | ------------------------------------------------------------------------ 10 | 11 | Running a brainf*ck interpreter in CPython:: 12 | 13 | $ cd bf 14 | $ python tutorial_bf.py tutorial_99.b 15 | 16 | Creating a C interpreter for brainf*ck using RPython 17 | (requires that pypy source is installed):: 18 | 19 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 20 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 21 | tutorial_bf.py 22 | 23 | Running a brainf*ck interpreter translated to C via RPython:: 24 | 25 | $ ./tutorial_bf-c tutorial_99.b 26 | 27 | Creating a C interpreter for brainf*ck with tracing-JIT compiler using 28 | RPython (requires that pypy source is installed):: 29 | 30 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 31 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 32 | --opt=jit tutorial_bf_jit.py 33 | 34 | Running:: 35 | 36 | $ ./tutorial_bf_jit-c tutorial_99.b 37 | 38 | A more optimized version:: 39 | 40 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 41 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 42 | --opt=jit tutorial_bf_jit_opt.py 43 | $ ./tutorial_bf_jit-c tutorial_99.b 44 | 45 | ------------------------------------------------------------------------ 46 | References 47 | ------------------------------------------------------------------------ 48 | 49 | - http://morepypy.blogspot.com/2011/04/tutorial-writing-interpreter-with-pypy.html 50 | - http://morepypy.blogspot.co.uk/2011/04/tutorial-part-2-adding-jit.html 51 | 52 | -------------------------------------------------------------------------------- /asm_toy_1/simple_asm.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | from rpython.rlib.rarithmetic import string_to_int as stoi 5 | 6 | def mainloop( insts ): 7 | pc = 0 8 | rf = RegisterFile() 9 | 10 | while pc < len( insts ): 11 | 12 | inst, f0, f1, f2 = insts[ pc ] 13 | 14 | if inst == 'addiu': 15 | rd, rs, imm = int(f0[1:]), int(f1[1:]), stoi(f2,base=16) 16 | rf[ rd ] = rf[ rs ] + imm 17 | 18 | elif inst == 'addu': 19 | rd, rs, rt = int(f0[1:]), int(f1[1:]), int(f2[1:]) 20 | rf[ rd ] = rf[ rs ] + rf[ rt ] 21 | 22 | elif inst == 'print': 23 | _, _, rt = f0, f1, int(f2[1:]) 24 | result = f2 + ' = ' + str( rf[rt] ) + '\n' 25 | os.write( 1, result ) 26 | 27 | pc += 1 28 | 29 | #----------------------------------------------------------------------- 30 | # RegisterFile 31 | #----------------------------------------------------------------------- 32 | class RegisterFile( object ): 33 | def __init__( self ): 34 | self.regs = [0] * 32 35 | def __getitem__( self, idx ): 36 | return self.regs[idx] 37 | def __setitem__( self, idx, value ): 38 | self.regs[idx] = value 39 | 40 | #----------------------------------------------------------------------- 41 | # parse 42 | #----------------------------------------------------------------------- 43 | def parse( fp ): 44 | insts = [] 45 | line = '' 46 | last = None 47 | 48 | for char in fp.read(): 49 | if char == '\n' and line: 50 | inst, f0, f1, f2 = line.split(' ',3 ) 51 | insts.append([inst, f0, f1, f2]) 52 | line = '' 53 | last = None 54 | elif char != ',' and not (last == char == ' '): 55 | line += char 56 | last = char 57 | 58 | return insts 59 | 60 | #----------------------------------------------------------------------- 61 | # run 62 | #----------------------------------------------------------------------- 63 | def run(fp): 64 | program = parse( fp ) 65 | mainloop(program) 66 | 67 | #----------------------------------------------------------------------- 68 | # entry_point 69 | #----------------------------------------------------------------------- 70 | def entry_point(argv): 71 | try: 72 | filename = argv[1] 73 | except IndexError: 74 | print "You must supply a filename" 75 | return 1 76 | 77 | run(open(filename, 'r')) 78 | return 0 79 | 80 | #----------------------------------------------------------------------- 81 | # target 82 | #----------------------------------------------------------------------- 83 | # Enables RPython translation of our interpreter. 84 | def target( *args ): 85 | return entry_point, None 86 | 87 | #----------------------------------------------------------------------- 88 | # main 89 | #----------------------------------------------------------------------- 90 | # Enables CPython simulation of our interpreter. 91 | if __name__ == "__main__": 92 | entry_point( sys.argv ) 93 | -------------------------------------------------------------------------------- /parc_interpreter/interp_asm_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import subprocess 3 | sys.path.append('/Users/dmlockhart/vc/git-brg/parc/pymtl') 4 | 5 | from inspect import getmembers, ismodule, isfunction 6 | 7 | import pisa.pisa_inst_addu_test 8 | import pisa.pisa_inst_subu_test 9 | import pisa.pisa_inst_and_test 10 | import pisa.pisa_inst_or_test 11 | import pisa.pisa_inst_xor_test 12 | import pisa.pisa_inst_nor_test 13 | import pisa.pisa_inst_slt_test 14 | import pisa.pisa_inst_sltu_test 15 | 16 | import pisa.pisa_inst_addiu_test 17 | import pisa.pisa_inst_andi_test 18 | import pisa.pisa_inst_ori_test 19 | import pisa.pisa_inst_xori_test 20 | import pisa.pisa_inst_slti_test 21 | import pisa.pisa_inst_sltiu_test 22 | 23 | import pisa.pisa_inst_sll_test 24 | import pisa.pisa_inst_srl_test 25 | import pisa.pisa_inst_sra_test 26 | import pisa.pisa_inst_sllv_test 27 | import pisa.pisa_inst_srlv_test 28 | import pisa.pisa_inst_srav_test 29 | 30 | import pisa.pisa_inst_lui_test 31 | import pisa.pisa_inst_j_test 32 | import pisa.pisa_inst_jal_test 33 | import pisa.pisa_inst_jr_test 34 | import pisa.pisa_inst_jalr_test 35 | 36 | import pisa.pisa_inst_beq_test 37 | import pisa.pisa_inst_bne_test 38 | import pisa.pisa_inst_blez_test 39 | import pisa.pisa_inst_bltz_test 40 | import pisa.pisa_inst_bgez_test 41 | import pisa.pisa_inst_bgtz_test 42 | 43 | import pisa.pisa_inst_lw_test 44 | import pisa.pisa_inst_lh_test 45 | import pisa.pisa_inst_lhu_test 46 | import pisa.pisa_inst_lb_test 47 | import pisa.pisa_inst_lbu_test 48 | 49 | import pisa.pisa_inst_sw_test 50 | import pisa.pisa_inst_sh_test 51 | import pisa.pisa_inst_sb_test 52 | 53 | #----------------------------------------------------------------------- 54 | # files 55 | #----------------------------------------------------------------------- 56 | 57 | asm = 'test.s' 58 | rpython_binary = './interp_asm_jit-c' 59 | cpython_script = 'python interp_asm_jit.py' 60 | 61 | def pytest_funcarg__cmd(request): 62 | if request.config.option.cpython: return cpython_script 63 | else: return rpython_binary 64 | 65 | #----------------------------------------------------------------------- 66 | # collect tests 67 | #----------------------------------------------------------------------- 68 | tests = [] 69 | test_names = [] 70 | 71 | for mname, module in getmembers( pisa, ismodule ): 72 | if not (mname.startswith('pisa_inst') and mname.endswith('test')): 73 | continue 74 | for func_name, func in getmembers( module, isfunction ): 75 | if not (func_name.startswith('gen') and func.__module__.endswith( mname )): 76 | continue 77 | test = func() 78 | 79 | name = '{}.{}'.format( mname, func_name ) 80 | test_names.append( name ) 81 | 82 | if isinstance( test, str ): 83 | tests.append( test ) 84 | else: 85 | tests.append( ''.join( test ) ) 86 | 87 | 88 | #----------------------------------------------------------------------- 89 | # test_asm 90 | #----------------------------------------------------------------------- 91 | import pytest 92 | @pytest.mark.parametrize( 'test_str', tests, ids=test_names ) 93 | def test_asm( cmd, test_str ): 94 | 95 | with open(asm, 'w') as asm_file: 96 | lines = test_str.split('\n') 97 | for line in lines: 98 | asm_file.write( line.lstrip()+'\n' ) 99 | 100 | try: 101 | subprocess.check_call( 102 | (cmd+' '+asm).split(), 103 | env={'PYTHONPATH': '/Users/dmlockhart/vc/hg-opensource/pypy'} 104 | ) 105 | except subprocess.CalledProcessError as e: 106 | print test_str 107 | raise e 108 | 109 | print "DONE" 110 | 111 | -------------------------------------------------------------------------------- /bf/tutorial_bf_jit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from tutorial_bf import Tape, parse 5 | 6 | #----------------------------------------------------------------------- 7 | # jitdriver 8 | #----------------------------------------------------------------------- 9 | # So that you can still run this module under standard CPython, I add this 10 | # import guard that creates a dummy class instead. 11 | try: 12 | from rpython.rlib.jit import JitDriver 13 | except ImportError: 14 | class JitDriver(object): 15 | def __init__ ( self, **kw ): pass 16 | def jit_merge_point( self, **kw ): pass 17 | def can_enter_jit ( self, **kw ): pass 18 | 19 | jitdriver = JitDriver(greens=['pc', 'program', 'bracket_map'], reds=['tape']) 20 | 21 | #----------------------------------------------------------------------- 22 | # mainloop 23 | #----------------------------------------------------------------------- 24 | def mainloop(program, bracket_map): 25 | pc = 0 26 | tape = Tape() 27 | 28 | while pc < len(program): 29 | 30 | # Annotation needed by jit 31 | 32 | jitdriver.jit_merge_point( 33 | pc=pc, 34 | tape=tape, 35 | program=program, 36 | bracket_map=bracket_map 37 | ) 38 | 39 | code = program[pc] 40 | 41 | if code == ">": 42 | tape.advance() 43 | 44 | elif code == "<": 45 | tape.devance() 46 | 47 | elif code == "+": 48 | tape.inc() 49 | 50 | elif code == "-": 51 | tape.dec() 52 | 53 | elif code == ".": 54 | # print 55 | #sys.stdout.write(chr(tape.get())) # EXAMPLE 1 56 | os.write(1, chr(tape.get())) 57 | 58 | elif code == ",": 59 | # read from stdin 60 | #tape.set(ord(sys.stdin.read(1))) # EXAMPLE 1 61 | tape.set(ord(os.read(0, 1)[0])) 62 | 63 | elif code == "[" and tape.get() == 0: 64 | # Skip forward to the matching ] 65 | pc = bracket_map[pc] 66 | 67 | elif code == "]" and tape.get() != 0: 68 | # Skip back to the matching [ 69 | pc = bracket_map[pc] 70 | 71 | pc += 1 72 | 73 | #----------------------------------------------------------------------- 74 | # jitpolicy 75 | #----------------------------------------------------------------------- 76 | def jitpolicy(driver): 77 | from rpython.jit.codewriter.policy import JitPolicy 78 | return JitPolicy() 79 | 80 | #----------------------------------------------------------------------- 81 | # run 82 | #----------------------------------------------------------------------- 83 | def run(fp): 84 | program_contents = "" 85 | while True: 86 | read = os.read(fp, 4096) 87 | if len(read) == 0: 88 | break 89 | program_contents += read 90 | os.close(fp) 91 | program, bm = parse(program_contents) 92 | mainloop(program, bm) 93 | 94 | #----------------------------------------------------------------------- 95 | # entry_point 96 | #----------------------------------------------------------------------- 97 | def entry_point(argv): 98 | try: 99 | filename = argv[1] 100 | except IndexError: 101 | print "You must supply a filename" 102 | return 1 103 | 104 | run(os.open(filename, os.O_RDONLY, 0777)) 105 | return 0 106 | 107 | #----------------------------------------------------------------------- 108 | # target 109 | #----------------------------------------------------------------------- 110 | def target(*args): 111 | return entry_point, None 112 | 113 | #----------------------------------------------------------------------- 114 | # main 115 | #----------------------------------------------------------------------- 116 | if __name__ == "__main__": 117 | entry_point(sys.argv) 118 | -------------------------------------------------------------------------------- /bf/tutorial_bf_jit_opt.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from tutorial_bf import Tape, parse 5 | 6 | #----------------------------------------------------------------------- 7 | # jitdriver 8 | #----------------------------------------------------------------------- 9 | # So that you can still run this module under standard CPython, I add this 10 | # import guard that creates a dummy class instead. 11 | try: 12 | from rpython.rlib.jit import JitDriver, purefunction 13 | except ImportError: 14 | class JitDriver(object): 15 | def __init__ ( self, **kw ): pass 16 | def jit_merge_point( self, **kw ): pass 17 | def can_enter_jit ( self, **kw ): pass 18 | def purefunction(f): return f 19 | 20 | jitdriver = JitDriver(greens=['pc', 'program', 'bracket_map'], reds=['tape']) 21 | 22 | #----------------------------------------------------------------------- 23 | # get_matching_bracket 24 | #----------------------------------------------------------------------- 25 | @purefunction 26 | def get_matching_bracket(bracket_map, pc): 27 | return bracket_map[pc] 28 | 29 | #----------------------------------------------------------------------- 30 | # mainloop 31 | #----------------------------------------------------------------------- 32 | def mainloop(program, bracket_map): 33 | pc = 0 34 | tape = Tape() 35 | 36 | while pc < len(program): 37 | 38 | # Annotation needed by jit 39 | 40 | jitdriver.jit_merge_point( 41 | pc=pc, 42 | tape=tape, 43 | program=program, 44 | bracket_map=bracket_map 45 | ) 46 | 47 | code = program[pc] 48 | 49 | if code == ">": 50 | tape.advance() 51 | 52 | elif code == "<": 53 | tape.devance() 54 | 55 | elif code == "+": 56 | tape.inc() 57 | 58 | elif code == "-": 59 | tape.dec() 60 | 61 | elif code == ".": 62 | # print 63 | #sys.stdout.write(chr(tape.get())) # EXAMPLE 1 64 | os.write(1, chr(tape.get())) 65 | 66 | elif code == ",": 67 | # read from stdin 68 | #tape.set(ord(sys.stdin.read(1))) # EXAMPLE 1 69 | tape.set(ord(os.read(0, 1)[0])) 70 | 71 | elif code == "[" and tape.get() == 0: 72 | # Skip forward to the matching ] 73 | pc = get_matching_bracket(bracket_map, pc) 74 | 75 | 76 | elif code == "]" and tape.get() != 0: 77 | # Skip back to the matching [ 78 | pc = get_matching_bracket(bracket_map, pc) 79 | 80 | pc += 1 81 | 82 | #----------------------------------------------------------------------- 83 | # jitpolicy 84 | #----------------------------------------------------------------------- 85 | def jitpolicy(driver): 86 | from rpython.jit.codewriter.policy import JitPolicy 87 | return JitPolicy() 88 | 89 | #----------------------------------------------------------------------- 90 | # run 91 | #----------------------------------------------------------------------- 92 | def run(fp): 93 | program_contents = "" 94 | while True: 95 | read = os.read(fp, 4096) 96 | if len(read) == 0: 97 | break 98 | program_contents += read 99 | os.close(fp) 100 | program, bm = parse(program_contents) 101 | mainloop(program, bm) 102 | 103 | #----------------------------------------------------------------------- 104 | # entry_point 105 | #----------------------------------------------------------------------- 106 | def entry_point(argv): 107 | try: 108 | filename = argv[1] 109 | except IndexError: 110 | print "You must supply a filename" 111 | return 1 112 | 113 | run(os.open(filename, os.O_RDONLY, 0777)) 114 | return 0 115 | 116 | #----------------------------------------------------------------------- 117 | # target 118 | #----------------------------------------------------------------------- 119 | def target(*args): 120 | return entry_point, None 121 | 122 | #----------------------------------------------------------------------- 123 | # main 124 | #----------------------------------------------------------------------- 125 | if __name__ == "__main__": 126 | entry_point(sys.argv) 127 | -------------------------------------------------------------------------------- /bf/tutorial_bf.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyPy tutorial by Andrew Brown 3 | example1.py - Python BF interpreter 4 | 5 | """ 6 | 7 | import sys 8 | import os 9 | 10 | #----------------------------------------------------------------------- 11 | # mainloop 12 | #----------------------------------------------------------------------- 13 | def mainloop(program, bracket_map): 14 | pc = 0 15 | tape = Tape() 16 | 17 | while pc < len(program): 18 | 19 | code = program[pc] 20 | 21 | if code == ">": 22 | tape.advance() 23 | 24 | elif code == "<": 25 | tape.devance() 26 | 27 | elif code == "+": 28 | tape.inc() 29 | 30 | elif code == "-": 31 | tape.dec() 32 | 33 | elif code == ".": 34 | # print 35 | #sys.stdout.write(chr(tape.get())) # EXAMPLE 1 36 | os.write(1, chr(tape.get())) 37 | 38 | elif code == ",": 39 | # read from stdin 40 | #tape.set(ord(sys.stdin.read(1))) # EXAMPLE 1 41 | tape.set(ord(os.read(0, 1)[0])) 42 | 43 | elif code == "[" and tape.get() == 0: 44 | # Skip forward to the matching ] 45 | pc = bracket_map[pc] 46 | 47 | elif code == "]" and tape.get() != 0: 48 | # Skip back to the matching [ 49 | pc = bracket_map[pc] 50 | 51 | pc += 1 52 | 53 | #----------------------------------------------------------------------- 54 | # Tape 55 | #----------------------------------------------------------------------- 56 | class Tape(object): 57 | def __init__(self): 58 | self.thetape = [0] 59 | self.position = 0 60 | 61 | def get(self): 62 | return self.thetape[self.position] 63 | def set(self, val): 64 | self.thetape[self.position] = val 65 | def inc(self): 66 | self.thetape[self.position] += 1 67 | def dec(self): 68 | self.thetape[self.position] -= 1 69 | def advance(self): 70 | self.position += 1 71 | if len(self.thetape) <= self.position: 72 | self.thetape.append(0) 73 | def devance(self): 74 | self.position -= 1 75 | 76 | #----------------------------------------------------------------------- 77 | # parse 78 | #----------------------------------------------------------------------- 79 | def parse(program): 80 | parsed = [] 81 | bracket_map = {} 82 | leftstack = [] 83 | 84 | pc = 0 85 | for char in program: 86 | if char in ('[', ']', '<', '>', '+', '-', ',', '.'): 87 | parsed.append(char) 88 | 89 | if char == '[': 90 | leftstack.append(pc) 91 | elif char == ']': 92 | left = leftstack.pop() 93 | right = pc 94 | bracket_map[left] = right 95 | bracket_map[right] = left 96 | pc += 1 97 | 98 | return "".join(parsed), bracket_map 99 | 100 | #======================================================================= 101 | # EXAMPLE 1 102 | #======================================================================= 103 | # 104 | #def run(input): 105 | # program, map = parse(input.read()) 106 | # mainloop(program, map) 107 | # 108 | #if __name__ == "__main__": 109 | # run(open(sys.argv[1], 'r')) 110 | 111 | #======================================================================= 112 | # EXAMPLE 2 113 | #======================================================================= 114 | 115 | #----------------------------------------------------------------------- 116 | # run 117 | #----------------------------------------------------------------------- 118 | def run(fp): 119 | program, bm = parse(fp.read()) 120 | mainloop(program, bm) 121 | 122 | #----------------------------------------------------------------------- 123 | # entry_point 124 | #----------------------------------------------------------------------- 125 | def entry_point(argv): 126 | try: 127 | filename = argv[1] 128 | except IndexError: 129 | print "You must supply a filename" 130 | return 1 131 | 132 | run(open(filename, 'r')) 133 | return 0 134 | 135 | #----------------------------------------------------------------------- 136 | # target 137 | #----------------------------------------------------------------------- 138 | def target(*args): 139 | return entry_point, None 140 | 141 | #----------------------------------------------------------------------- 142 | # main 143 | #----------------------------------------------------------------------- 144 | if __name__ == "__main__": 145 | entry_point(sys.argv) 146 | 147 | -------------------------------------------------------------------------------- /asm_toy_2/interp_asm.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | from rpython.rlib.rarithmetic import string_to_int as stoi 5 | 6 | #----------------------------------------------------------------------- 7 | # reg_map 8 | #----------------------------------------------------------------------- 9 | 10 | reg_map = { 11 | '$0' : 0, '$1' : 1, '$2' : 2, '$3' : 3, 12 | '$4' : 4, '$5' : 5, '$6' : 6, '$7' : 7, 13 | '$8' : 8, '$9' : 9, '$10' : 10, '$11' : 11, 14 | '$12' : 12, '$13' : 13, '$14' : 14, '$15' : 15, 15 | '$16' : 16, '$17' : 17, '$18' : 18, '$19' : 19, 16 | '$20' : 20, '$21' : 21, '$22' : 22, '$23' : 23, 17 | '$24' : 24, '$25' : 25, '$26' : 26, '$27' : 27, 18 | '$28' : 28, '$29' : 29, '$30' : 30, '$31' : 31, 19 | 20 | 'r0' : 0, 'r1' : 1, 'r2' : 2, 'r3' : 3, 21 | 'r4' : 4, 'r5' : 5, 'r6' : 6, 'r7' : 7, 22 | 'r8' : 8, 'r9' : 9, 'r10' : 10, 'r11' : 11, 23 | 'r12' : 12, 'r13' : 13, 'r14' : 14, 'r15' : 15, 24 | 'r16' : 16, 'r17' : 17, 'r18' : 18, 'r19' : 19, 25 | 'r20' : 20, 'r21' : 21, 'r22' : 22, 'r23' : 23, 26 | 'r24' : 24, 'r25' : 25, 'r26' : 26, 'r27' : 27, 27 | 'r28' : 28, 'r29' : 29, 'r30' : 30, 'r31' : 31, 28 | 29 | 'zero' : 0, 'at' : 1, 'v0' : 2, 'v1' : 3, 30 | 'a0' : 4, 'a1' : 5, 'a2' : 6, 'a3' : 7, 31 | 'a4' : 8, 'a5' : 9, 'a6' : 10, 'a7' : 11, 32 | 't0' : 12, 't1' : 13, 't2' : 14, 't3' : 15, 33 | # 't0' : 8, 't1' : 9, 't2' : 10, 't3' : 11, # old abi 34 | # 't4' : 12, 't5' : 13, 't6' : 14, 't7' : 15, # old abi 35 | 's0' : 16, 's1' : 17, 's2' : 18, 's3' : 19, 36 | 's4' : 20, 's5' : 21, 's6' : 22, 's7' : 23, 37 | 't8' : 24, 't9' : 25, 'k0' : 26, 'k1' : 27, 38 | 'gp' : 28, 'sp' : 29, 's8' : 30, 'ra' : 31, 39 | 40 | 'status' : 1, 41 | 'mngr2proc' : 1, 42 | 'proc2mngr' : 2, 43 | 'statsen' : 10, 44 | 'coreid' : 17, 45 | } 46 | 47 | 48 | #----------------------------------------------------------------------- 49 | # mainloop 50 | #----------------------------------------------------------------------- 51 | def mainloop( insts, src, sink ): 52 | pc = 0 53 | rf = RegisterFile() 54 | 55 | src_ptr = sink_ptr = 0 56 | 57 | while pc < len( insts ): 58 | 59 | inst, fields = insts[pc].split( ' ', 1 ) 60 | 61 | if inst == 'mfc0': 62 | f0, f1 = fields.split( ' ', 1 ) 63 | f1 = f1.strip() # TODO: clean this up 64 | rt, rd = reg_map[ f0 ], reg_map[ f1 ] 65 | if rd == 1: 66 | rf[ rt ] = src[ src_ptr ] 67 | src_ptr += 1 68 | elif rd == 17: pass 69 | else: raise Exception('Invalid mfc0 destination!') 70 | 71 | elif inst == 'mtc0': 72 | f0, f1 = fields.split( ' ', 1 ) 73 | f1 = f1.strip() # TODO: clean this up 74 | rt, rd = reg_map[ f0 ], reg_map[ f1 ] 75 | if rd == 1: pass 76 | elif rd == 2: 77 | if sink[ sink_ptr ] != rf[ rt ]: 78 | print 'Instruction: '+insts[pc]+' failed!' 79 | raise Exception('Instruction: '+insts[pc]+' failed!') 80 | print 'SUCCESS: rf[' + str( rt ) + '] == ' + str( sink[ sink_ptr ] ) 81 | sink_ptr += 1 82 | elif rd == 10: pass 83 | else: raise Exception('Invalid mtc0 destination!') 84 | 85 | elif inst == 'addiu': 86 | f0, f1, f2 = fields.split( ' ', 3 ) 87 | rd, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=16 ) 88 | rf[ rd ] = rf[ rs ] + imm 89 | 90 | elif inst == 'addu': 91 | f0, f1, f2 = fields.split( ' ', 3 ) 92 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 93 | rf[ rd ] = rf[ rs ] + rf[ rt ] 94 | 95 | elif inst == 'print': 96 | rt = reg_map[ fields ] 97 | result = fields + ' = ' + str( rf[rt] ) 98 | print result 99 | 100 | pc += 1 101 | 102 | #----------------------------------------------------------------------- 103 | # RegisterFile 104 | #----------------------------------------------------------------------- 105 | class RegisterFile( object ): 106 | def __init__( self ): 107 | self.regs = [0] * 32 108 | def __getitem__( self, idx ): 109 | return self.regs[idx] 110 | def __setitem__( self, idx, value ): 111 | self.regs[idx] = value 112 | 113 | #----------------------------------------------------------------------- 114 | # parse 115 | #----------------------------------------------------------------------- 116 | COPY = 0 117 | COMMENT = 1 118 | MTC0 = 2 119 | MFC0 = 3 120 | def parse( fp ): 121 | 122 | insts = [] 123 | src = [] 124 | sink = [] 125 | 126 | inst_str = '' 127 | src_str = '' 128 | sink_str = '' 129 | 130 | last = None 131 | mode = COPY 132 | 133 | for char in fp.read(): 134 | 135 | if char == '\n': 136 | if inst_str: 137 | insts.append( inst_str ) 138 | inst_str = '' 139 | if src_str: 140 | src.append( stoi( src_str, base=0 ) ) 141 | src_str = '' 142 | if sink_str: 143 | sink.append( stoi( sink_str, base=0 ) ) 144 | sink_str = '' 145 | last = None 146 | mode = COPY 147 | 148 | elif char == '#': 149 | mode = COMMENT 150 | 151 | elif char == '<': 152 | mode = MFC0 153 | 154 | elif char == '>': 155 | mode = MTC0 156 | 157 | elif mode == COPY and char not in [',','(',')'] \ 158 | and not (last == char == ' '): 159 | inst_str += char 160 | last = char 161 | 162 | elif mode == MFC0: 163 | src_str += char 164 | 165 | elif mode == MTC0: 166 | sink_str += char 167 | 168 | return insts, src, sink 169 | 170 | #----------------------------------------------------------------------- 171 | # run 172 | #----------------------------------------------------------------------- 173 | def run(fp): 174 | program, src, sink = parse( fp ) 175 | mainloop( program, src, sink ) 176 | 177 | #----------------------------------------------------------------------- 178 | # entry_point 179 | #----------------------------------------------------------------------- 180 | def entry_point(argv): 181 | try: 182 | filename = argv[1] 183 | except IndexError: 184 | print "You must supply a filename" 185 | return 1 186 | 187 | run(open(filename, 'r')) 188 | return 0 189 | 190 | #----------------------------------------------------------------------- 191 | # target 192 | #----------------------------------------------------------------------- 193 | # Enables RPython translation of our interpreter. 194 | def target( *args ): 195 | return entry_point, None 196 | 197 | #----------------------------------------------------------------------- 198 | # main 199 | #----------------------------------------------------------------------- 200 | # Enables CPython simulation of our interpreter. 201 | if __name__ == "__main__": 202 | entry_point( sys.argv ) 203 | -------------------------------------------------------------------------------- /bf/tutorial_99.b: -------------------------------------------------------------------------------- 1 | # 99 bottles of beer in Brainf*ck 2 | # Copyright (C) 2008 Raphael Bois 3 | # 1671 brainf*ck instructions. 4 | # Published under GPL v2 5 | 6 | Initialization 7 | ++ Counter for loop (a) 8 | >+ unused 9 | >++ Counter for loop (b) 10 | > Flag for 'no more' 11 | >+ Flag for not 'no more' 12 | >>> (5) to (7) : temporary values 13 | ++++++++++[->+>+>++++++++++<<<]>>> 10 10 100 in (8) (9) (10) 14 | >++++++++++ 10 in (11) 15 | [- 16 | >+++++ 50 in (12) 17 | >++++++++++ 100 in (13) 18 | >+++++++++++ 110 in (14) 19 | >++++++++ 80 in (15) 20 | >++++++++ 80 in (16) 21 | >+++ 30 in (17) 22 | >++++ 40 in (18) 23 | >+ 10 in (19) 24 | <<<<<<<<] 25 | + 26 | >-- + 48 '0' plus 1 in (12) 27 | >++ + 102 'f' plus 1 in (13) 28 | >+++++ + 115 's' plus 1 in (14) 29 | >-- + 78 'N' plus 1 in (15) 30 | >++++ + 84 'T' plus 1 in (16) 31 | >++ + 32 ' ' plus 1 in (17) 32 | >++++ + 44 comma plus 1 in (18) 33 | > + 10 LF plus 1 in (19) 34 | 35 | stuff for writing parts of the song 36 | >+ select stuff 37 | >+ select stuff 38 | >+ write song part 3 39 | >++ write song part 1 40 | >+ write song part 2 41 | >+ Flag for 'end of song' 42 | >++ Flag for not 'end of song' 43 | 44 | All bytes are at val plus 1 45 | Go back to (7) with final initialization step (remove 1 to all bytes) 46 | [-<] 47 | 48 | <<<<<<< at (0) 49 | [ loop (a) 50 | - 51 | 52 | >> at (2) 53 | [ loop (b) 54 | 55 | >>>>>>>> at (10) 56 | [ start loop 57 | 58 | <<<<<<< at (3) 59 | [->[-] 60 | print '(N|n)o more' 61 | >>>>>>>>>>>. '(N|n)' 62 | <----. 'o' 63 | >>>. ' ' 64 | <<<--. 'm' 65 | ++. 'o' 66 | +++.+ 'r' 67 | <-.+ 'e' 68 | <<+<<<<<<<< 69 | ]+> at (4) 70 | [-<[-]>>>>> at (9) 71 | prints number (using (9) and (10)) 72 | [>>>+<<<<+<+<+>>>-]<<<[->>>+<<<]> at (6) 73 | [>>>>>>+<<<<<<-]>>>>>[[-]>.<]<<<<[>>>>>-<<<<<-]>> at (9) 74 | [<<+<+<+>>>>-]<<<<[->>>>+<<<<]> at (6) 75 | [>>>>>>+<<<<<<-]>>>>>>.<<<<<[>>>>>-<<<<<-] at (7) 76 | 77 | memorize in (11) if (10) not 1 78 | >>>[-<<<+<+>>>>]<<<<[->>>>+<<<<]>-[[-]>>>>+<<<<]<<< at (4) 79 | ]+ 80 | 81 | >>>>>>>> at (12) 82 | print ' bottle(s) of beer' 83 | >>>>>. ' ' 84 | <<<<----. 'b' 85 | >----. 'o' 86 | +++++..- 'tt' 87 | <++++++++++. 'l' 88 | -------. 'e' 89 | <<[[-]>>>.<<<]>> 's' if (11)==1 ie if (10)!=1 90 | >>>>. ' ' 91 | <<<----. 'o' 92 | <+. 'f' 93 | >>>>. ' ' 94 | <<<<----. 'b' 95 | +++..+ 'ee' 96 | >+++.+ 'r' 97 | 98 | [>] at (20) 99 | 100 | +>+>[->+<<-<- 101 | print ' on the wall' DOT LF LF 102 | <<<. ' ' 103 | <<<----. 'o' 104 | -. 'n' 105 | >>>. ' ' 106 | <<<++++++. 't' 107 | <++. 'h' 108 | ---. 'e' 109 | >>>>. ' ' 110 | <<<+++. 'w' 111 | <----. 'a' 112 | +++++++++++.. 'll' 113 | ------>---- reset to 'f' and 's' 114 | >---------- ---------- ---------- -- sets (15) to 'N' 115 | 116 | >>>++.-- DOT 117 | >.. LF LF 118 | >>>] at (22) 119 | 120 | >>>[->[-]<<<<<<<[<]<[-]>>[>]>>>>>]+ if end of song reset bottles counter 121 | >[-<[-] at (25) 122 | <<<< at (21) 123 | [->>[->+<<<<- 124 | print ' on the wall' COMMA ' ' 125 | <<<. ' ' 126 | <<<----. 'o' 127 | -. 'n' 128 | >>>. ' ' 129 | <<<++++++. 't' 130 | <++. 'h' 131 | ---. 'e' 132 | >>>>. ' ' 133 | <<<+++. 'w' 134 | <----. 'a' 135 | +++++++++++.. 'll' 136 | 137 | ------>---- reset (13) and (14) to 'f' and 's' 138 | >++++++++++ ++++++++++ ++++++++++ ++ sets (15) to 'n' 139 | 140 | >>>. comma 141 | <. ' ' 142 | >>>>>>]<<]< at (20) 143 | 144 | [->>>>[-<<+< at (21) 145 | <<<++.-- DOT 146 | >. LF 147 | 148 | [<]<<<<<<<< at (3) 149 | [->[-]<]+> at (4) 150 | [-<[-]> 151 | >>>>>>>>>>>>. 'T' 152 | <<<-----. 'a' 153 | ++++++++++. 'k' 154 | ------. 'e' 155 | >>>>. ' ' 156 | <<<----. 'o' 157 | -. 'n' 158 | <. 'e' 159 | >>>>. ' ' 160 | <<<<-. 'd' 161 | >+. 'o' 162 | ++++++++. 'w' 163 | ---------. 'n' 164 | >>>. ' ' 165 | <<<<---. 'a' 166 | >. 'n' 167 | <+++. 'd' 168 | >>>>. ' ' 169 | <<<++. 'p' 170 | <---. 'a' 171 | >+++.. 'ss' 172 | >>>. ' ' 173 | <<<<++++++++. 'i' 174 | >+. 't' 175 | >>>. ' ' 176 | <<<<--------. 'a' 177 | >--. 'r' 178 | ---. 'o' 179 | ++++++. 'u' 180 | -------. 'n' 181 | <+++. 'd' 182 | ++>+++++ reset (13) and (14) to 'f' and 's' 183 | >>>>. comma 184 | <. ' ' 185 | 186 | [<]<<<<<<< at (4) 187 | ]+ 188 | 189 | >>>>>> at (10) 190 | decrements values 191 | -<<<+>>[<<[-]<+<+>>>>-]<<<<[>-<[-]]>[->>>+<<<]>[->->+++++++++<<]>>> at (10) 192 | 193 | >>[>]>>>>] at (24) 194 | <<<<] at (20) 195 | 196 | >>>>>>]+ at (26) 197 | 198 | <<<<<<<[<]< at (10) 199 | ] 200 | +<+ 201 | <<<<<<+< at (2) 202 | - 203 | ] 204 | 205 | print 'Go to the store and buy some more' comma ' ' 206 | 207 | >>>>>>>>>>[>]>>>>> at (25) 208 | [->[-]<]+> at (26) 209 | [-<[-] 210 | <<<<<<<<< at (16) 211 | -------------. 'G' 212 | <<----. 'o' 213 | >>>. ' ' 214 | <<<+++++. 't' 215 | -----. 'o' 216 | >>>. ' ' 217 | <<<+++++. 't' 218 | <++. 'h' 219 | ---. 'e' 220 | >>>>. ' ' 221 | <<<-. 's' 222 | +. 't' 223 | -----. 'o' 224 | +++. 'r' 225 | <. 'e' 226 | >>>>. ' ' 227 | <<<<----. 'a' 228 | >----. 'n' 229 | <+++. 'd' 230 | >>>>. ' ' 231 | <<<<--. 'b' 232 | >+++++++. 'u' 233 | ++++. 'y' 234 | >>>. ' ' 235 | <<<------. 's' 236 | ----. 'o' 237 | --. 'm' 238 | <+++. 'e' 239 | >>>>. ' ' 240 | <<<. 'm' 241 | ++. 'o' 242 | +++.+ 'r' 243 | <.+ 'e' 244 | >>>>>. coma 245 | <. ' ' 246 | >>>>>>>>> 247 | ]+ 248 | 249 | Initialize last loop to print final '99 bottles of beer on the wall' DOT 250 | <[-]+<[-]<[-]<[-]+<<< at (19) 251 | [<]<[-]<[-]<[-]<[-] at (7) 252 | ++++++++++[->+>+>++++++++++<<<]>->->- 253 | <<<<<<[-]+<[-]<+<< at (0) 254 | ] 255 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | RPython Experiments 3 | =============================================================================== 4 | 5 | A collection of toy interpreters in RPython for learning about the the 6 | RPython translation toolchain. 7 | 8 | ------------------------------------------------------------------------------- 9 | Project Subdirectories 10 | ------------------------------------------------------------------------------- 11 | 12 | The following directories contain experimental interpreters for executing 13 | textual files. They serve no purpose other than to learn more about the 14 | capabilities of the RPython translation toolchain. 15 | 16 | - parc_interp: An interpreter for the complete PARC ISA. 17 | - asm_toy_2: A toy interpreter for (less) simple PARC assembly files. 18 | - asm_toy_1: A toy interpreter for (very) simple PARC assembly files. 19 | - bf: A simple interpreter for a toy language. 20 | 21 | Please see the README files in each subdirectory for more information. 22 | 23 | ------------------------------------------------------------------------------- 24 | Beginner RPython References 25 | ------------------------------------------------------------------------------- 26 | 27 | - http://www.wilfred.me.uk/blog/2014/05/24/r-python-for-fun-and-profit/ 28 | - http://morepypy.blogspot.com/2011/04/tutorial-writing-interpreter-with-pypy.html 29 | - http://morepypy.blogspot.co.uk/2011/04/tutorial-part-2-adding-jit.html 30 | - https://bitbucket.org/brownan/pypy-tutorial/ 31 | - http://pie-interpreter.blogspot.com/2012/12/how-to-make-new-interpreter-with-pypy.html 32 | - http://indefinitestudies.org/2010/02/08/creating-a-toy-virtual-machine-with-pypy 33 | 34 | ------------------------------------------------------------------------------- 35 | Advanced RPython References 36 | ------------------------------------------------------------------------------- 37 | 38 | - http://morepypy.blogspot.com/2011/03/controlling-tracing-of-interpreter-with.html 39 | - http://morepypy.blogspot.com/2011/03/controlling-tracing-of-interpreter-with_15.html 40 | - http://morepypy.blogspot.com/2011/03/controlling-tracing-of-interpreter-with_21.html 41 | - http://morepypy.blogspot.com/2011/03/controlling-tracing-of-interpreter-with_26.html 42 | - http://bitbucket.org/pypy/extradoc/raw/extradoc/talk/icooolps2011/bolz-hints.pdf 43 | - http://pypy.readthedocs.org/en/latest/jit/pyjitpl5.html 44 | - http://morepypy.blogspot.com/2010/06/jit-for-regular-expression-matching.html 45 | - https://github.com/samgiles/naulang/blob/master/naulang/compiler/parser.py 46 | - https://github.com/alex/rply 47 | 48 | ------------------------------------------------------------------------------- 49 | Quick Start: A Very Basic Language Interpreter 50 | ------------------------------------------------------------------------------- 51 | 52 | Running a brainf*ck interpreter in CPython:: 53 | 54 | $ cd bf 55 | $ python tutorial_bf.py tutorial_99.b 56 | 57 | Creating a C interpreter for brainf*ck using RPython 58 | (requires that pypy source is installed):: 59 | 60 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 61 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 62 | tutorial_bf.py 63 | 64 | Running a brainf*ck interpreter translated to C via RPython:: 65 | 66 | $ ./tutorial_bf-c tutorial_99.b 67 | 68 | Creating a C interpreter for brainf*ck with tracing-JIT compiler using 69 | RPython (requires that pypy source is installed):: 70 | 71 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 72 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 73 | --opt=jit tutorial_bf_jit.py 74 | 75 | Running:: 76 | 77 | $ ./tutorial_bf_jit-c tutorial_99.b 78 | 79 | A more optimized version:: 80 | 81 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 82 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 83 | --opt=jit tutorial_bf_jit_opt.py 84 | $ ./tutorial_bf_jit-c tutorial_99.b 85 | 86 | ------------------------------------------------------------------------------- 87 | Toy ISA Interpreter 1 88 | ------------------------------------------------------------------------------- 89 | 90 | This interpreter is a very basic foundation for an ISA interpreter, it 91 | only includes addiu, addu, and print instructions. It is useful seeing 92 | the minimal code needed to make a simple ISA interpreting simulator:: 93 | 94 | $ cd asm_toy_1 95 | 96 | CPython:: 97 | 98 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' \ 99 | python simple_asm.py asm_00.s 100 | 101 | RPython with no JIT:: 102 | 103 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 104 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 105 | simple_asm.py 106 | $ ./simple_asm-c asm_00.s 107 | 108 | ------------------------------------------------------------------------------- 109 | Toy ISA Interpreter 2 110 | ------------------------------------------------------------------------------- 111 | 112 | This interpreter is a similar to the asm_toy_1, but includes mtc0 and 113 | mfc0 instructions for testing, as well as demonstrates how a register 114 | map can be used to simplify the interpreter design:: 115 | 116 | $ cd asm_toy_2 117 | 118 | CPython:: 119 | 120 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' \ 121 | python interp_asm.py asm_04.s 122 | 123 | RPython with no JIT:: 124 | 125 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 126 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 127 | interp_asm.py 128 | $ ./interp_asm-c asm_04.s 129 | 130 | ------------------------------------------------------------------------------- 131 | PARC ISA Interpreter 132 | ------------------------------------------------------------------------------- 133 | 134 | This interpreter is a full interpreter for the PARC ISA! Note that as 135 | an interpreter it expects assembly files, **not** binaries! 136 | 137 | It includes a test runner script which can run a full array of PARC 138 | assembly tests, it requires that PyMTL is installed on the local system. 139 | To run the assembly tests with CPython:: 140 | 141 | $ cd parc_interpreter 142 | $ py.test interp_asm_test.py --verbose --cpython 143 | 144 | Before running the assembly tests with RPython, first compile the C 145 | implmementation. 146 | 147 | The C implementation **without** JIT (should take ~30 seconds):: 148 | 149 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 150 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 151 | interp_asm_jit.py 152 | 153 | The C implementation **with** JIT (should take ~500 seconds):: 154 | 155 | $ PYTHONPATH='/Users/dmlockhart/vc/hg-opensource/pypy' python \ 156 | ~/vc/hg-opensource/pypy/rpython/translator/goal/translate.py \ 157 | --opt=jit \ 158 | interp_asm_jit.py 159 | 160 | The run the tests:: 161 | 162 | $ py.test interp_asm_test.py --verbose 163 | 164 | The the interpreter on an assembly file directly:: 165 | 166 | $ ./interp_asm_jit-c test.s 167 | 168 | ------------------------------------------------------------------------------- 169 | A List of Untranslatable Python Constructs (and Fixes) 170 | ------------------------------------------------------------------------------- 171 | 172 | Fails:: 173 | int( some_str, base=16 ) 174 | Translates, but fails during execution:: 175 | int( some_str, 16 ) 176 | Works:: 177 | rpython.rlib.rarithmetic.string_to_int( some_str, base=16 ) 178 | 179 | Fails:: 180 | line.split() 181 | Works:: 182 | line.split(' ', 3) 183 | 184 | Fails:: 185 | with open( filename, 'rb' ) as file_obj: ... 186 | Works:: 187 | file_obj = open( filename, 'rb ) 188 | file_obj.close() 189 | 190 | Fails:: 191 | string = string.ljust( nchars, '0' ) 192 | Works:: 193 | string = '0'*( nchars - len(string) ) + string 194 | 195 | Fails:: 196 | my_array[start_idx:] 197 | Works:: 198 | assert start_idx >= 0 199 | my_array[start_idx:] 200 | 201 | Fails:: 202 | assert obj.attr >= 0 203 | my_array[obj.attr:] 204 | Works:: 205 | start_idx = obj.attr 206 | assert start_idx >= 0 207 | my_array[start_idx:] 208 | 209 | Fails:: 210 | section_name = start.partition('\0')[0] 211 | Works:: 212 | section_name = start.split( '\0', 1 )[0] 213 | 214 | Fails:: 215 | if my_str != None: do_something() 216 | Works:: 217 | if my_str != '': do_something() 218 | 219 | -------------------------------------------------------------------------------- /parc_interpreter/interp_asm_jit.py: -------------------------------------------------------------------------------- 1 | #======================================================================= 2 | # interp_asm_jit.py 3 | #======================================================================= 4 | # RPython implementation of Parc ISA interpreter, with JIT. 5 | 6 | import sys 7 | import os 8 | 9 | from rpython.rlib.rarithmetic import string_to_int as stoi 10 | from rpython.rlib.jit import JitDriver 11 | 12 | #======================================================================= 13 | # Utility Functions 14 | #======================================================================= 15 | 16 | #----------------------------------------------------------------------- 17 | # sext 18 | #----------------------------------------------------------------------- 19 | # Sign extend 16-bit immediate fields. 20 | def sext( value ): 21 | if value & 0x8000: 22 | return 0xFFFF0000 | value 23 | return value 24 | 25 | #----------------------------------------------------------------------- 26 | # sext_byte 27 | #----------------------------------------------------------------------- 28 | # Sign extend 8-bit immediate fields. 29 | def sext_byte( value ): 30 | if value & 0x80: 31 | return 0xFFFFFF00 | value 32 | return value 33 | 34 | #----------------------------------------------------------------------- 35 | # signed 36 | #----------------------------------------------------------------------- 37 | def signed( value ): 38 | if value & 0x80000000: 39 | twos_complement = ~value + 1 40 | return -trim( twos_complement ) 41 | return value 42 | 43 | #----------------------------------------------------------------------- 44 | # trim 45 | #----------------------------------------------------------------------- 46 | # Trim arithmetic to 16-bit values. 47 | def trim( value ): 48 | return value & 0xFFFFFFFF 49 | 50 | #----------------------------------------------------------------------- 51 | # trim_5 52 | #----------------------------------------------------------------------- 53 | # Trim arithmetic to 5-bit values. 54 | def trim_5( value ): 55 | return value & 0b11111 56 | 57 | #----------------------------------------------------------------------- 58 | # register_inst 59 | #----------------------------------------------------------------------- 60 | # Utility decorator for building decode table. 61 | def register_inst( func ): 62 | prefix, suffix = func.func_name.split('_') 63 | assert prefix == 'execute' 64 | decode_table[ suffix ] = func 65 | return func 66 | 67 | #======================================================================= 68 | # Regsiter Definitions 69 | #======================================================================= 70 | 71 | reg_map = { 72 | '$0' : 0, '$1' : 1, '$2' : 2, '$3' : 3, 73 | '$4' : 4, '$5' : 5, '$6' : 6, '$7' : 7, 74 | '$8' : 8, '$9' : 9, '$10' : 10, '$11' : 11, 75 | '$12' : 12, '$13' : 13, '$14' : 14, '$15' : 15, 76 | '$16' : 16, '$17' : 17, '$18' : 18, '$19' : 19, 77 | '$20' : 20, '$21' : 21, '$22' : 22, '$23' : 23, 78 | '$24' : 24, '$25' : 25, '$26' : 26, '$27' : 27, 79 | '$28' : 28, '$29' : 29, '$30' : 30, '$31' : 31, 80 | 81 | 'r0' : 0, 'r1' : 1, 'r2' : 2, 'r3' : 3, 82 | 'r4' : 4, 'r5' : 5, 'r6' : 6, 'r7' : 7, 83 | 'r8' : 8, 'r9' : 9, 'r10' : 10, 'r11' : 11, 84 | 'r12' : 12, 'r13' : 13, 'r14' : 14, 'r15' : 15, 85 | 'r16' : 16, 'r17' : 17, 'r18' : 18, 'r19' : 19, 86 | 'r20' : 20, 'r21' : 21, 'r22' : 22, 'r23' : 23, 87 | 'r24' : 24, 'r25' : 25, 'r26' : 26, 'r27' : 27, 88 | 'r28' : 28, 'r29' : 29, 'r30' : 30, 'r31' : 31, 89 | 90 | 'zero' : 0, 'at' : 1, 'v0' : 2, 'v1' : 3, 91 | 'a0' : 4, 'a1' : 5, 'a2' : 6, 'a3' : 7, 92 | 'a4' : 8, 'a5' : 9, 'a6' : 10, 'a7' : 11, 93 | 't0' : 12, 't1' : 13, 't2' : 14, 't3' : 15, 94 | # 't0' : 8, 't1' : 9, 't2' : 10, 't3' : 11, # old abi 95 | # 't4' : 12, 't5' : 13, 't6' : 14, 't7' : 15, # old abi 96 | 's0' : 16, 's1' : 17, 's2' : 18, 's3' : 19, 97 | 's4' : 20, 's5' : 21, 's6' : 22, 's7' : 23, 98 | 't8' : 24, 't9' : 25, 'k0' : 26, 'k1' : 27, 99 | 'gp' : 28, 'sp' : 29, 's8' : 30, 'ra' : 31, 100 | 101 | 'status' : 1, 102 | 'mngr2proc' : 1, 103 | 'proc2mngr' : 2, 104 | 'statsen' : 10, 105 | 'coreid' : 17, 106 | } 107 | 108 | reset_vector = 0x00000400 109 | data_section = 0x00002000 110 | 111 | #======================================================================= 112 | # Instruction Definitions 113 | #======================================================================= 114 | 115 | decode_table = {} 116 | 117 | #----------------------------------------------------------------------- 118 | # Coprocessor 0 Instructions 119 | #----------------------------------------------------------------------- 120 | 121 | #----------------------------------------------------------------------- 122 | # mfc0 123 | #----------------------------------------------------------------------- 124 | @register_inst 125 | def execute_mfc0( s, src, sink, rf, fields ): 126 | f0, f1 = fields.split( ' ', 1 ) 127 | rt, rd = reg_map[ f0 ], reg_map[ f1 ] 128 | if rd == 1: 129 | rf[ rt ] = src[ s.src_ptr ] 130 | s.src_ptr += 1 131 | elif rd == 17: pass 132 | else: raise Exception('Invalid mfc0 destination!') 133 | s.pc += 1 134 | 135 | #----------------------------------------------------------------------- 136 | # mtc0 137 | #----------------------------------------------------------------------- 138 | @register_inst 139 | def execute_mtc0( s, src, sink, rf, fields ): 140 | f0, f1 = fields.split( ' ', 1 ) 141 | rt, rd = reg_map[ f0 ], reg_map[ f1 ] 142 | if rd == 1: pass 143 | elif rd == 2: 144 | if sink[ s.sink_ptr ] != rf[ rt ]: 145 | print 'sink:', sink[ s.sink_ptr ], 'rf:', rf[ rt ] 146 | raise Exception('Instruction: mtc0 failed!') 147 | print 'SUCCESS: rf[' + str( rt ) + '] == ' + str( sink[ s.sink_ptr ] ) 148 | s.sink_ptr += 1 149 | elif rd == 10: pass 150 | else: raise Exception('Invalid mtc0 destination!') 151 | s.pc += 1 152 | 153 | #----------------------------------------------------------------------- 154 | # Register-register arithmetic, logical, and comparison instructions 155 | #----------------------------------------------------------------------- 156 | 157 | #----------------------------------------------------------------------- 158 | # addu 159 | #----------------------------------------------------------------------- 160 | @register_inst 161 | def execute_addu( s, src, sink, rf, fields ): 162 | f0, f1, f2 = fields.split( ' ', 3 ) 163 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 164 | rf[ rd ] = trim( rf[ rs ] + rf[ rt ] ) 165 | s.pc += 1 166 | 167 | #----------------------------------------------------------------------- 168 | # print 169 | #----------------------------------------------------------------------- 170 | @register_inst 171 | def execute_print( s, src, sink, rf, fields ): 172 | rt = reg_map[ fields ] 173 | result = fields + ' = ' + str( rf[rt] ) 174 | print result 175 | s.pc += 1 176 | 177 | #----------------------------------------------------------------------- 178 | # subu 179 | #----------------------------------------------------------------------- 180 | @register_inst 181 | def execute_subu( s, src, sink, rf, fields ): 182 | f0, f1, f2 = fields.split( ' ', 3 ) 183 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 184 | rf[rd] = trim( rf[rs] - rf[rt] ) 185 | s.pc += 1 186 | 187 | #----------------------------------------------------------------------- 188 | # and 189 | #----------------------------------------------------------------------- 190 | @register_inst 191 | def execute_and( s, src, sink, rf, fields ): 192 | f0, f1, f2 = fields.split( ' ', 3 ) 193 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 194 | rf[rd] = rf[rs] & rf[rt] 195 | s.pc += 1 196 | 197 | #----------------------------------------------------------------------- 198 | # or 199 | #----------------------------------------------------------------------- 200 | @register_inst 201 | def execute_or( s, src, sink, rf, fields ): 202 | f0, f1, f2 = fields.split( ' ', 3 ) 203 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 204 | rf[rd] = rf[rs] | rf[rt] 205 | s.pc += 1 206 | 207 | #----------------------------------------------------------------------- 208 | # xor 209 | #----------------------------------------------------------------------- 210 | @register_inst 211 | def execute_xor( s, src, sink, rf, fields ): 212 | f0, f1, f2 = fields.split( ' ', 3 ) 213 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 214 | rf[rd] = rf[rs] ^ rf[rt] 215 | s.pc += 1 216 | 217 | #----------------------------------------------------------------------- 218 | # nor 219 | #----------------------------------------------------------------------- 220 | @register_inst 221 | def execute_nor( s, src, sink, rf, fields ): 222 | f0, f1, f2 = fields.split( ' ', 3 ) 223 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 224 | rf[rd] = trim( ~(rf[rs] | rf[rt]) ) 225 | s.pc += 1 226 | 227 | #----------------------------------------------------------------------- 228 | # slt 229 | #----------------------------------------------------------------------- 230 | @register_inst 231 | def execute_slt( s, src, sink, rf, fields ): 232 | f0, f1, f2 = fields.split( ' ', 3 ) 233 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 234 | rf[rd] = signed( rf[rs] ) < signed( rf[rt] ) 235 | s.pc += 1 236 | 237 | #----------------------------------------------------------------------- 238 | # sltu 239 | #----------------------------------------------------------------------- 240 | @register_inst 241 | def execute_sltu( s, src, sink, rf, fields ): 242 | f0, f1, f2 = fields.split( ' ', 3 ) 243 | rd, rs, rt = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 244 | rf[rd] = rf[rs] < rf[rt] 245 | s.pc += 1 246 | 247 | #----------------------------------------------------------------------- 248 | # Register-immediate arithmetic, logical, and comparison instructions 249 | #----------------------------------------------------------------------- 250 | 251 | #----------------------------------------------------------------------- 252 | # addiu 253 | #----------------------------------------------------------------------- 254 | @register_inst 255 | def execute_addiu( s, src, sink, rf, fields ): 256 | f0, f1, f2 = fields.split( ' ', 3 ) 257 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 258 | rf[ rt ] = trim( rf[ rs ] + sext( imm ) ) 259 | s.pc += 1 260 | 261 | #----------------------------------------------------------------------- 262 | # andi 263 | #----------------------------------------------------------------------- 264 | @register_inst 265 | def execute_andi( s, src, sink, rf, fields ): 266 | f0, f1, f2 = fields.split( ' ', 3 ) 267 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 268 | rf[rt] = rf[rs] & imm 269 | s.pc += 1 270 | 271 | #----------------------------------------------------------------------- 272 | # ori 273 | #----------------------------------------------------------------------- 274 | @register_inst 275 | def execute_ori( s, src, sink, rf, fields ): 276 | f0, f1, f2 = fields.split( ' ', 3 ) 277 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 278 | rf[rt] = rf[rs] | imm 279 | s.pc += 1 280 | 281 | #----------------------------------------------------------------------- 282 | # xori 283 | #----------------------------------------------------------------------- 284 | @register_inst 285 | def execute_xori( s, src, sink, rf, fields ): 286 | f0, f1, f2 = fields.split( ' ', 3 ) 287 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 288 | rf[rt] = rf[rs] ^ imm 289 | s.pc += 1 290 | 291 | #----------------------------------------------------------------------- 292 | # slti 293 | #----------------------------------------------------------------------- 294 | @register_inst 295 | def execute_slti( s, src, sink, rf, fields ): 296 | f0, f1, f2 = fields.split( ' ', 3 ) 297 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 298 | rf[rt] = signed( rf[rs] ) < signed( sext(imm) ) 299 | s.pc += 1 300 | 301 | #----------------------------------------------------------------------- 302 | # sltiu 303 | #----------------------------------------------------------------------- 304 | @register_inst 305 | def execute_sltiu( s, src, sink, rf, fields ): 306 | f0, f1, f2 = fields.split( ' ', 3 ) 307 | rt, rs, imm = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 308 | rf[rt] = rf[rs] < sext(imm) 309 | s.pc += 1 310 | 311 | #----------------------------------------------------------------------- 312 | # Shift instructions 313 | #----------------------------------------------------------------------- 314 | 315 | #----------------------------------------------------------------------- 316 | # sll 317 | #----------------------------------------------------------------------- 318 | @register_inst 319 | def execute_sll( s, src, sink, rf, fields ): 320 | f0, f1, f2 = fields.split( ' ', 3 ) 321 | rd, rt, shamt = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 322 | rf[rd] = trim( rf[rt] << shamt ) 323 | s.pc += 1 324 | 325 | #----------------------------------------------------------------------- 326 | # srl 327 | #----------------------------------------------------------------------- 328 | @register_inst 329 | def execute_srl( s, src, sink, rf, fields ): 330 | f0, f1, f2 = fields.split( ' ', 3 ) 331 | rd, rt, shamt = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 332 | rf[rd] = rf[rt] >> shamt 333 | s.pc += 1 334 | 335 | #----------------------------------------------------------------------- 336 | # sra 337 | #----------------------------------------------------------------------- 338 | @register_inst 339 | def execute_sra( s, src, sink, rf, fields ): 340 | f0, f1, f2 = fields.split( ' ', 3 ) 341 | rd, rt, shamt = reg_map[ f0 ], reg_map[ f1 ], stoi( f2, base=0 ) 342 | rf[rd] = trim( signed( rf[rt] ) >> shamt ) 343 | s.pc += 1 344 | 345 | #----------------------------------------------------------------------- 346 | # sllv 347 | #----------------------------------------------------------------------- 348 | @register_inst 349 | def execute_sllv( s, src, sink, rf, fields ): 350 | f0, f1, f2 = fields.split( ' ', 3 ) 351 | rd, rt, rs = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 352 | rf[rd] = trim( rf[rt] << trim_5( rf[rs] ) ) 353 | s.pc += 1 354 | 355 | #----------------------------------------------------------------------- 356 | # srlv 357 | #----------------------------------------------------------------------- 358 | @register_inst 359 | def execute_srlv( s, src, sink, rf, fields ): 360 | f0, f1, f2 = fields.split( ' ', 3 ) 361 | rd, rt, rs = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 362 | rf[rd] = rf[rt] >> trim_5( rf[rs] ) 363 | s.pc += 1 364 | 365 | #----------------------------------------------------------------------- 366 | # srav 367 | #----------------------------------------------------------------------- 368 | @register_inst 369 | def execute_srav( s, src, sink, rf, fields ): 370 | f0, f1, f2 = fields.split( ' ', 3 ) 371 | rd, rt, rs = reg_map[ f0 ], reg_map[ f1 ], reg_map[ f2 ] 372 | # TODO: should it really be masked like this? 373 | rf[rd] = trim( signed( rf[rt] ) >> trim_5( rf[rs] ) ) 374 | s.pc += 1 375 | 376 | #----------------------------------------------------------------------- 377 | # Unconditional jump instructions 378 | #----------------------------------------------------------------------- 379 | 380 | #----------------------------------------------------------------------- 381 | # j 382 | #----------------------------------------------------------------------- 383 | @register_inst 384 | def execute_j( s, src, sink, rf, fields ): 385 | if fields in s.symtable: jtarg = s.symtable[ fields ] 386 | else: jtarg = stoi( fields, base=0 ) 387 | #s.pc = ((s.pc + 4) & 0xF0000000) | (jtarg << 2) 388 | # TODO: HACKY 389 | s.pc = ((s.pc + 1) & 0xF0000000) | jtarg 390 | 391 | #----------------------------------------------------------------------- 392 | # jal 393 | #----------------------------------------------------------------------- 394 | @register_inst 395 | def execute_jal( s, src, sink, rf, fields ): 396 | if fields in s.symtable: jtarg = s.symtable[ fields ] 397 | else: jtarg = stoi( fields, base=0 ) 398 | #rf[31] = s.pc + 4 399 | #s.pc = ((s.pc + 4) & 0xF0000000) | (jtarg << 2) 400 | # TODO: HACKY 401 | rf[31] = 4*(s.pc + 1) + reset_vector 402 | s.pc = ( (s.pc + 1) & 0xF0000000) | jtarg 403 | 404 | #----------------------------------------------------------------------- 405 | # jr 406 | #----------------------------------------------------------------------- 407 | @register_inst 408 | def execute_jr( s, src, sink, rf, fields ): 409 | rs = reg_map[ fields ] 410 | s.pc = rf[rs] 411 | 412 | #----------------------------------------------------------------------- 413 | # jalr 414 | #----------------------------------------------------------------------- 415 | @register_inst 416 | def execute_jalr( s, src, sink, rf, fields ): 417 | f0, f1 = fields.split( ' ', 2 ) 418 | rd, rs = reg_map[ f0 ], reg_map[ f1 ] 419 | #rf[rd] = s.pc + 4 420 | # TODO: HACKY 421 | rf[rd] = 4*(s.pc + 1) + reset_vector 422 | s.pc = rf[rs] 423 | 424 | #----------------------------------------------------------------------- 425 | # lui 426 | #----------------------------------------------------------------------- 427 | @register_inst 428 | def execute_lui( s, src, sink, rf, fields ): 429 | f0, f1 = fields.split( ' ', 2 ) 430 | rt, imm = reg_map[ f0 ], stoi( f1, base=0 ) 431 | rf[rt] = imm << 16 432 | s.pc += 1 433 | 434 | 435 | #----------------------------------------------------------------------- 436 | # Conditional branch instructions 437 | #----------------------------------------------------------------------- 438 | 439 | #----------------------------------------------------------------------- 440 | # beq 441 | #----------------------------------------------------------------------- 442 | @register_inst 443 | def execute_beq( s, src, sink, rf, fields ): 444 | f0, f1, f2 = fields.split( ' ', 3 ) 445 | rt, rs = reg_map[ f0 ], reg_map[ f1 ] 446 | if f2 in s.symtable: imm = s.symtable[ f2 ] 447 | else: imm = stoi( f2, base=0 ) 448 | 449 | # TODO: assuming label is absolute, not offset! 450 | if rf[rs] == rf[rt]: 451 | s.pc = imm 452 | #s.pc = (s.pc + 1 + sext(imm)) << 2 453 | else: 454 | s.pc += 1 455 | 456 | #----------------------------------------------------------------------- 457 | # bne 458 | #----------------------------------------------------------------------- 459 | @register_inst 460 | def execute_bne( s, src, sink, rf, fields ): 461 | f0, f1, f2 = fields.split( ' ', 3 ) 462 | rt, rs = reg_map[ f0 ], reg_map[ f1 ] 463 | if f2 in s.symtable: imm = s.symtable[ f2 ] 464 | else: imm = stoi( f2, base=0 ) 465 | 466 | # TODO: assuming label is absolute, not offset! 467 | if rf[rs] != rf[rt]: 468 | s.pc = imm 469 | #s.pc = (s.pc + 1 + sext(imm)) << 2 470 | else: 471 | s.pc += 1 472 | 473 | #----------------------------------------------------------------------- 474 | # blez 475 | #----------------------------------------------------------------------- 476 | @register_inst 477 | def execute_blez( s, src, sink, rf, fields ): 478 | f0, f1 = fields.split( ' ', 2 ) 479 | rs = reg_map[ f0 ] 480 | if f1 in s.symtable: imm = s.symtable[ f1 ] 481 | else: imm = stoi( f1, base=0 ) 482 | 483 | # TODO: assuming label is absolute, not offset! 484 | if signed( rf[rs] ) <= 0: 485 | s.pc = imm 486 | #s.pc = (s.pc + 1 + sext(imm)) << 2 487 | else: 488 | s.pc += 1 489 | 490 | #----------------------------------------------------------------------- 491 | # bgtz 492 | #----------------------------------------------------------------------- 493 | @register_inst 494 | def execute_bgtz( s, src, sink, rf, fields ): 495 | f0, f1 = fields.split( ' ', 2 ) 496 | rs = reg_map[ f0 ] 497 | if f1 in s.symtable: imm = s.symtable[ f1 ] 498 | else: imm = stoi( f1, base=0 ) 499 | 500 | # TODO: assuming label is absolute, not offset! 501 | if signed( rf[rs] ) > 0: 502 | s.pc = imm 503 | #s.pc = (s.pc + 1 + sext(imm)) << 2 504 | else: 505 | s.pc += 1 506 | 507 | #----------------------------------------------------------------------- 508 | # bltz 509 | #----------------------------------------------------------------------- 510 | @register_inst 511 | def execute_bltz( s, src, sink, rf, fields ): 512 | f0, f1 = fields.split( ' ', 2 ) 513 | rs = reg_map[ f0 ] 514 | if f1 in s.symtable: imm = s.symtable[ f1 ] 515 | else: imm = stoi( f1, base=0 ) 516 | 517 | # TODO: assuming label is absolute, not offset! 518 | if signed( rf[rs] ) < 0: 519 | s.pc = imm 520 | #s.pc = (s.pc + 1 + sext(imm)) << 2 521 | else: 522 | s.pc += 1 523 | 524 | #----------------------------------------------------------------------- 525 | # bgez 526 | #----------------------------------------------------------------------- 527 | @register_inst 528 | def execute_bgez( s, src, sink, rf, fields ): 529 | f0, f1 = fields.split( ' ', 2 ) 530 | rs = reg_map[ f0 ] 531 | if f1 in s.symtable: imm = s.symtable[ f1 ] 532 | else: imm = stoi( f1, base=0 ) 533 | 534 | # TODO: assuming label is absolute, not offset! 535 | if signed( rf[rs] ) >= 0: 536 | s.pc = imm 537 | #s.pc = (s.pc + 1 + sext(imm)) << 2 538 | else: 539 | s.pc += 1 540 | 541 | #----------------------------------------------------------------------- 542 | # Load instructions 543 | #----------------------------------------------------------------------- 544 | 545 | #----------------------------------------------------------------------- 546 | # lw 547 | #----------------------------------------------------------------------- 548 | @register_inst 549 | def execute_lw( s, src, sink, rf, fields ): 550 | f0, f1, f2 = fields.split( ' ', 3 ) 551 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 552 | addr = rf[rs] + sext(imm) - data_section 553 | rf[rt] = s.mem.read( addr, 4 ) 554 | s.pc += 1 555 | 556 | #----------------------------------------------------------------------- 557 | # lh 558 | #----------------------------------------------------------------------- 559 | @register_inst 560 | def execute_lh( s, src, sink, rf, fields ): 561 | f0, f1, f2 = fields.split( ' ', 3 ) 562 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 563 | addr = rf[rs] + sext(imm) - data_section 564 | rf[rt] = sext( s.mem.read( addr, 2 ) ) 565 | s.pc += 1 566 | 567 | #----------------------------------------------------------------------- 568 | # lhu 569 | #----------------------------------------------------------------------- 570 | @register_inst 571 | def execute_lhu( s, src, sink, rf, fields ): 572 | f0, f1, f2 = fields.split( ' ', 3 ) 573 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 574 | addr = rf[rs] + sext(imm) - data_section 575 | rf[rt] = s.mem.read( addr, 2 ) 576 | s.pc += 1 577 | 578 | #----------------------------------------------------------------------- 579 | # lb 580 | #----------------------------------------------------------------------- 581 | @register_inst 582 | def execute_lb( s, src, sink, rf, fields ): 583 | f0, f1, f2 = fields.split( ' ', 3 ) 584 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 585 | addr = rf[rs] + sext(imm) - data_section 586 | rf[rt] = sext_byte( s.mem.read( addr, 1 ) ) 587 | s.pc += 1 588 | 589 | #----------------------------------------------------------------------- 590 | # lbu 591 | #----------------------------------------------------------------------- 592 | @register_inst 593 | def execute_lbu( s, src, sink, rf, fields ): 594 | f0, f1, f2 = fields.split( ' ', 3 ) 595 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 596 | addr = rf[rs] + sext(imm) - data_section 597 | rf[rt] = s.mem.read( addr, 1 ) 598 | s.pc += 1 599 | 600 | #----------------------------------------------------------------------- 601 | # Store instructions 602 | #----------------------------------------------------------------------- 603 | 604 | #----------------------------------------------------------------------- 605 | # sw 606 | #----------------------------------------------------------------------- 607 | @register_inst 608 | def execute_sw( s, src, sink, rf, fields ): 609 | f0, f1, f2 = fields.split( ' ', 3 ) 610 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 611 | addr = rf[rs] + sext(imm) - data_section 612 | s.mem.write( addr, 4, rf[rt] ) 613 | s.pc += 1 614 | 615 | #----------------------------------------------------------------------- 616 | # sh 617 | #----------------------------------------------------------------------- 618 | @register_inst 619 | def execute_sh( s, src, sink, rf, fields ): 620 | f0, f1, f2 = fields.split( ' ', 3 ) 621 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 622 | addr = rf[rs] + sext(imm) - data_section 623 | s.mem.write( addr, 2, rf[rt] ) 624 | s.pc += 1 625 | 626 | #----------------------------------------------------------------------- 627 | # sb 628 | #----------------------------------------------------------------------- 629 | @register_inst 630 | def execute_sb( s, src, sink, rf, fields ): 631 | f0, f1, f2 = fields.split( ' ', 3 ) 632 | rt, imm, rs = reg_map[ f0 ], stoi( f1, base=0 ), reg_map[ f2 ] 633 | addr = rf[rs] + sext(imm) - data_section 634 | s.mem.write( addr, 1, rf[rt] ) 635 | s.pc += 1 636 | 637 | #======================================================================= 638 | # Main Loop 639 | #======================================================================= 640 | 641 | #----------------------------------------------------------------------- 642 | # jit 643 | #----------------------------------------------------------------------- 644 | 645 | jitdriver = JitDriver( greens =['pc','insts',], 646 | reds =['state','symtable','src','sink',] 647 | ) 648 | 649 | def jitpolicy(driver): 650 | from rpython.jit.codewriter.policy import JitPolicy 651 | return JitPolicy() 652 | 653 | #----------------------------------------------------------------------- 654 | # mainloop 655 | #----------------------------------------------------------------------- 656 | def mainloop( insts, memory, symtable, src, sink ): 657 | s = State( memory, symtable ) 658 | 659 | # main interpreter loop 660 | 661 | while s.pc < len( insts ): 662 | 663 | # jit hint: jit_merge_point indicates start of opcode dispatch 664 | 665 | jitdriver.jit_merge_point( 666 | pc = s.pc, 667 | state = s, 668 | insts = insts, 669 | symtable = symtable, 670 | src = src, 671 | sink = sink, 672 | ) 673 | 674 | old = s.pc 675 | 676 | # skip nop instructions 677 | 678 | if insts[s.pc] == 'nop': 679 | inst = 'nop' 680 | s.pc += 1 681 | 682 | # instruction dispatch 683 | 684 | else: 685 | inst, fields = insts[s.pc].split( ' ', 1 ) 686 | decode_table[inst]( s, src, sink, s.rf, fields ) 687 | 688 | print old, ']]]', inst 689 | 690 | # jit hint: can_enter_jit indicates end of an application level loop 691 | 692 | if s.pc < old: 693 | jitdriver.can_enter_jit( 694 | pc = s.pc, 695 | state = s, 696 | insts = insts, 697 | symtable = symtable, 698 | src = src, 699 | sink = sink, 700 | ) 701 | 702 | # verify we successfully completed our program 703 | 704 | if s.sink_ptr != len( sink ): 705 | raise Exception('Failed to successfully receive all sink tokens!') 706 | 707 | #----------------------------------------------------------------------- 708 | # RegisterFile 709 | #----------------------------------------------------------------------- 710 | class RegisterFile( object ): 711 | def __init__( self ): 712 | self.regs = [0] * 32 713 | def __getitem__( self, idx ): 714 | return self.regs[idx] 715 | def __setitem__( self, idx, value ): 716 | self.regs[idx] = value 717 | 718 | #----------------------------------------------------------------------- 719 | # Memory 720 | #----------------------------------------------------------------------- 721 | class Memory( object ): 722 | def __init__( self ): 723 | self.data = [' ']*2**10 724 | 725 | def read( self, start_addr, num_bytes ): 726 | value = 0 727 | for i in range( num_bytes-1, -1, -1 ): 728 | value = value << 8 729 | value = value | ord( self.data[ start_addr + i ] ) 730 | return value 731 | 732 | def write( self, start_addr, num_bytes, value ): 733 | for i in range( num_bytes ): 734 | self.data[ start_addr + i ] = chr(value & 0xFF) 735 | value = value >> 8 736 | 737 | #----------------------------------------------------------------------- 738 | # State 739 | #----------------------------------------------------------------------- 740 | class State( object ): 741 | def __init__( self, memory, symtable ): 742 | self.src_ptr = 0 743 | self.sink_ptr = 0 744 | self.pc = 0 745 | self.rf = RegisterFile() 746 | self.mem = memory 747 | self.symtable = symtable 748 | 749 | #----------------------------------------------------------------------- 750 | # parse 751 | #----------------------------------------------------------------------- 752 | COPY = 0 753 | COMMENT = 1 754 | MTC0 = 2 755 | MFC0 = 3 756 | HI_LO = 4 757 | HI = 5 758 | LO = 6 759 | DATA = 7 760 | def parse( fp ): 761 | 762 | insts = [] 763 | src = [] 764 | sink = [] 765 | symtable = {} 766 | hi = {} 767 | lo = {} 768 | data = [] 769 | 770 | inst_str = '' 771 | src_str = '' 772 | sink_str = '' 773 | 774 | temp_str = '' 775 | 776 | last = None 777 | mode = COPY 778 | 779 | for char in fp.read(): 780 | 781 | if char == '\n': 782 | if inst_str: 783 | insts.append( inst_str.strip() ) 784 | inst_str = '' 785 | if src_str: 786 | src.append( stoi( src_str, base=0 ) ) 787 | src_str = '' 788 | if sink_str: 789 | sink.append( stoi( sink_str, base=0 ) ) 790 | sink_str = '' 791 | if temp_str: 792 | data.append( temp_str ) 793 | temp_str = '' 794 | last = None 795 | mode = COPY 796 | 797 | elif char == '#': 798 | mode = COMMENT 799 | 800 | elif mode == COPY and char == '<': 801 | mode = MFC0 802 | 803 | elif mode == COPY and char == '>': 804 | mode = MTC0 805 | 806 | elif mode == COPY and char == ':': 807 | symtable[ inst_str ] = len( insts ) 808 | inst_str = '' 809 | mode = COMMENT 810 | 811 | elif mode == COPY and char == '%': 812 | temp_str = '' 813 | mode = HI_LO 814 | 815 | elif mode == COPY and char == '.': 816 | temp_str = '' 817 | mode = DATA 818 | 819 | elif mode == COPY and char == '(': 820 | if last != ' ': 821 | inst_str += ' ' 822 | 823 | elif mode == COPY and char not in [',',')'] \ 824 | and not (last == char == ' '): 825 | inst_str += char 826 | last = char 827 | 828 | elif mode == MFC0: 829 | src_str += char 830 | 831 | elif mode == MTC0: 832 | sink_str += char 833 | 834 | elif mode == DATA: 835 | temp_str += char 836 | if temp_str == 'data': 837 | mode, temp_str = COMMENT, '' 838 | 839 | elif mode == HI_LO: 840 | temp_str += char 841 | if temp_str == 'hi': 842 | mode, temp_str = HI, '' 843 | elif temp_str == 'lo': 844 | mode, temp_str = LO, '' 845 | 846 | elif mode == HI and char not in ['[','(',' ']: 847 | if char in [']', ')']: 848 | hi[ temp_str ] = len( insts ) 849 | temp_str = '' 850 | else: 851 | temp_str += char 852 | 853 | elif mode == LO and char not in ['[','(',' ']: 854 | if char in [']', ')']: 855 | lo[ temp_str ] = len( insts ) 856 | temp_str = '' 857 | else: 858 | temp_str += char 859 | 860 | for label, pc in hi.items(): 861 | insts[ pc ] += ' ' + hex( symtable[ label ] >> 16 ) 862 | for label, pc in lo.items(): 863 | insts[ pc ] += ' ' + hex( symtable[ label ] & 0xFFFF ) 864 | 865 | addr = 0 866 | num_bytes = 0 867 | mem = Memory() 868 | for item in data: 869 | size, value = item.split(' ', 1) 870 | if size == 'word': num_bytes = 4 871 | elif size == 'half': num_bytes = 2 872 | elif size == 'hword': num_bytes = 2 873 | elif size == 'byte': num_bytes = 1 874 | else: raise Exception('Unsupported memory size!') 875 | mem.write( addr, num_bytes, stoi( value, base=0 ) ) 876 | addr += num_bytes 877 | 878 | print '*'*70 879 | print 'Instructions' 880 | print '============' 881 | for inst in insts: 882 | print inst 883 | print 884 | print 'Source' 885 | print '======' 886 | print src 887 | print 888 | print 'Sink' 889 | print '====' 890 | print sink 891 | print 892 | print 'Symbol Table' 893 | print '============' 894 | for key, value in symtable.items(): 895 | print key, value 896 | print '*'*70 897 | 898 | return insts, mem, symtable, src, sink 899 | 900 | #----------------------------------------------------------------------- 901 | # run 902 | #----------------------------------------------------------------------- 903 | def run(fp): 904 | program, memory, symtable, src, sink = parse( fp ) 905 | mainloop( program, memory, symtable, src, sink ) 906 | 907 | #----------------------------------------------------------------------- 908 | # entry_point 909 | #----------------------------------------------------------------------- 910 | def entry_point(argv): 911 | try: 912 | filename = argv[1] 913 | except IndexError: 914 | print "You must supply a filename" 915 | return 1 916 | 917 | run(open(filename, 'r')) 918 | return 0 919 | 920 | #----------------------------------------------------------------------- 921 | # target 922 | #----------------------------------------------------------------------- 923 | # Enables RPython translation of our interpreter. 924 | def target( *args ): 925 | return entry_point, None 926 | 927 | #----------------------------------------------------------------------- 928 | # main 929 | #----------------------------------------------------------------------- 930 | # Enables CPython simulation of our interpreter. 931 | if __name__ == "__main__": 932 | entry_point( sys.argv ) 933 | --------------------------------------------------------------------------------