:add lab7 spoc exercise related codes
This commit is contained in:
		
							parent
							
								
									69afb3405b
								
							
						
					
					
						commit
						f9b1bb3b66
					
				
							
								
								
									
										227
									
								
								related_info/lab7/lab7-spoc-exercise.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								related_info/lab7/lab7-spoc-exercise.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
# lab7 理解race condition
 | 
			
		||||
## x86模拟运行环境
 | 
			
		||||
x86.py是一个模拟执行基于汇编代码的多线程执行过程的模拟器。这里的汇编语法是基于很简单的x86汇编语法。
 | 
			
		||||
且没有包括OS的调度、context切换和中断处理过程。每条指令大小为一个byte。每个变量占4个byte
 | 
			
		||||
在硬件上模拟了4个通用寄存器:
 | 
			
		||||
```
 | 
			
		||||
%ax, %bx, %cx, %dx
 | 
			
		||||
```
 | 
			
		||||
一个程序计数器`pc`,一个堆栈寄存器`sp`,和一小部分指令:
 | 
			
		||||
```
 | 
			
		||||
mov immediate, register     #  immediate value --> register
 | 
			
		||||
mov memory, register        #  memory --> register
 | 
			
		||||
mov register, register      #  register --> register
 | 
			
		||||
mov register, memory        #  register -->  memory
 | 
			
		||||
mov immediate, memory       #  immediate value -->  memory
 | 
			
		||||
 | 
			
		||||
add immediate, register     # register  = register  + immediate
 | 
			
		||||
add register1, register2    # register2 = register2 + register1
 | 
			
		||||
sub immediate, register     # register  = register  - immediate
 | 
			
		||||
sub register1, register2    # register2 = register2 - register1
 | 
			
		||||
 | 
			
		||||
test immediate, register    # compare immediate and register (set condition codes)
 | 
			
		||||
test register, immediate    # compare register and immediate (set condition codes)
 | 
			
		||||
test register, register     # compare register and register  (set condition codes)
 | 
			
		||||
 | 
			
		||||
jne                         # jump if test'd values are not equal
 | 
			
		||||
je                          # jump if test'd values are equal
 | 
			
		||||
jlt                         # jump if test'd second is less than  first
 | 
			
		||||
jlte                        # jump if test'd second is less than or equal first
 | 
			
		||||
jgt                         # jump if test'd second is greater than first
 | 
			
		||||
jgte                        # jump if test'd second is greater than or equal first
 | 
			
		||||
 | 
			
		||||
xchg register, memory       # atomic exchange: 
 | 
			
		||||
                            #   put value of register into memory
 | 
			
		||||
                            #   return old contents of memory into reg
 | 
			
		||||
                            #   do both things atomically
 | 
			
		||||
 | 
			
		||||
nop                         # no op
 | 
			
		||||
halt						# stop
 | 
			
		||||
push memory or register     # push value in memory or from reg onto stack
 | 
			
		||||
                            # stack is defined by sp register
 | 
			
		||||
pop [register]              # pop value off stack (into optional register)
 | 
			
		||||
call label                  # call function at label
 | 
			
		||||
yield                       # switch to the next thread in the runqueue
 | 
			
		||||
```
 | 
			
		||||
注意: 
 | 
			
		||||
 - 'immediate' 格式是 $number
 | 
			
		||||
 - 'memory'    格式是 'number' 或 '(reg)' 或 'number(reg)' 或 'number(reg,reg)'
 | 
			
		||||
  - (%cx)       ->  在括号中的register cx 的值 形成 address
 | 
			
		||||
  - 2000        ->  2000 形成 address
 | 
			
		||||
  - 1000(%dx)   ->  1000 + dx的值 形成 address
 | 
			
		||||
  - 10(%ax,%bx) ->  10  + ax的值 + bx的值 形成 address
 | 
			
		||||
 - 'register' 格式是 %ax, %bx, %cx, %dx
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
下面是一个代码片段:
 | 
			
		||||
```
 | 
			
		||||
.main
 | 
			
		||||
mov 2000, %ax   # 取地址2000处的内存单元的内容,并赋值给ax 
 | 
			
		||||
add $1, %ax     # ax=ax+1
 | 
			
		||||
mov %ax, 2000   # 把ax的内容存储到地址2000处的内存单元中
 | 
			
		||||
halt
 | 
			
		||||
```
 | 
			
		||||
其含义如下
 | 
			
		||||
```
 | 
			
		||||
  2000        -> 2000      	形成地址 address
 | 
			
		||||
  (%cx)       -> cx的内容    	形成地址 address
 | 
			
		||||
  1000(%dx)   -> (1000+dx) 形成地址 address
 | 
			
		||||
  10(%ax,%bx) -> (10+ax+bx)	形成地址 address
 | 
			
		||||
  halt        -> 执行结束
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
循环执行的小例子片段
 | 
			
		||||
```
 | 
			
		||||
.main
 | 
			
		||||
.top
 | 
			
		||||
sub  $1,%dx
 | 
			
		||||
test $0,%dx     
 | 
			
		||||
jgte .top         
 | 
			
		||||
halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
x86.py模拟器运行参数
 | 
			
		||||
```
 | 
			
		||||
  -h, --help            show this help message and exit
 | 
			
		||||
  -s SEED, --seed=SEED  the random seed
 | 
			
		||||
  -t NUMTHREADS, --threads=NUMTHREADS
 | 
			
		||||
                        number of threads
 | 
			
		||||
  -p PROGFILE, --program=PROGFILE
 | 
			
		||||
                        source program (in .s)
 | 
			
		||||
  -i INTFREQ, --interrupt=INTFREQ
 | 
			
		||||
                        interrupt frequency
 | 
			
		||||
  -r, --randints        if interrupts are random
 | 
			
		||||
  -a ARGV, --argv=ARGV  comma-separated per-thread args (e.g., ax=1,ax=2 sets
 | 
			
		||||
                        thread 0 ax reg to 1 and thread 1 ax reg to 2);
 | 
			
		||||
                        specify multiple regs per thread via colon-separated
 | 
			
		||||
                        list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and
 | 
			
		||||
                        just cx for thread 1)
 | 
			
		||||
  -L LOADADDR, --loadaddr=LOADADDR
 | 
			
		||||
                        address where to load code
 | 
			
		||||
  -m MEMSIZE, --memsize=MEMSIZE
 | 
			
		||||
                        size of address space (KB)
 | 
			
		||||
  -M MEMTRACE, --memtrace=MEMTRACE
 | 
			
		||||
                        comma-separated list of addrs to trace (e.g.,
 | 
			
		||||
                        20000,20001)
 | 
			
		||||
  -R REGTRACE, --regtrace=REGTRACE
 | 
			
		||||
                        comma-separated list of regs to trace (e.g.,
 | 
			
		||||
                        ax,bx,cx,dx)
 | 
			
		||||
  -C, --cctrace         should we trace condition codes
 | 
			
		||||
  -S, --printstats      print some extra stats
 | 
			
		||||
  -v, --verbose         print some extra info
 | 
			
		||||
  -c, --compute         compute answers for me
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
执行举例
 | 
			
		||||
```
 | 
			
		||||
$ ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx
 | 
			
		||||
 | 
			
		||||
 2000      ax    bx          Thread 0
 | 
			
		||||
    ?       ?     ?
 | 
			
		||||
    ?       ?     ?   1000 mov 2000, %ax
 | 
			
		||||
    ?       ?     ?   1001 add $1, %ax
 | 
			
		||||
    ?       ?     ?   1002 mov %ax, 2000
 | 
			
		||||
    ?       ?     ?   1003 halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
如果加上参数 `-c`可得到具体执行结果
 | 
			
		||||
```
 | 
			
		||||
$ ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx -c
 | 
			
		||||
 | 
			
		||||
 2000      ax    bx          Thread 0
 | 
			
		||||
    0       0     0
 | 
			
		||||
    0       0     0   1000 mov 2000, %ax
 | 
			
		||||
    0       1     0   1001 add $1, %ax
 | 
			
		||||
    1       1     0   1002 mov %ax, 2000
 | 
			
		||||
    1       1     0   1003 halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
另外一个执行的例子
 | 
			
		||||
```
 | 
			
		||||
$ ./x86.py -p loop.s -t 1 -a dx=3 -R dx -C -c
 | 
			
		||||
 | 
			
		||||
   dx   >= >  <= <  != ==        Thread 0
 | 
			
		||||
    3   0  0  0  0  0  0
 | 
			
		||||
    2   0  0  0  0  0  0  1000 sub  $1,%dx
 | 
			
		||||
    2   1  1  0  0  1  0  1001 test $0,%dx
 | 
			
		||||
    2   1  1  0  0  1  0  1002 jgte .top
 | 
			
		||||
    1   1  1  0  0  1  0  1000 sub  $1,%dx
 | 
			
		||||
    1   1  1  0  0  1  0  1001 test $0,%dx
 | 
			
		||||
    1   1  1  0  0  1  0  1002 jgte .top
 | 
			
		||||
    0   1  1  0  0  1  0  1000 sub  $1,%dx
 | 
			
		||||
    0   1  0  1  0  0  1  1001 test $0,%dx
 | 
			
		||||
    0   1  0  1  0  0  1  1002 jgte .top
 | 
			
		||||
    0   1  0  1  0  0  1  1003 halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
多线程存在race condition 的例子 looping-race-nolock.s 
 | 
			
		||||
```
 | 
			
		||||
.main
 | 
			
		||||
.top
 | 
			
		||||
# critical section
 | 
			
		||||
mov 2000, %ax       # get the value at the address
 | 
			
		||||
add $1, %ax         # increment it
 | 
			
		||||
mov %ax, 2000       # store it back
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
执行结果:
 | 
			
		||||
```
 | 
			
		||||
$ ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -c
 | 
			
		||||
 | 
			
		||||
 2000      bx          Thread 0                Thread 1
 | 
			
		||||
    0       1
 | 
			
		||||
    0       1   1000 mov 2000, %ax
 | 
			
		||||
    0       1   1001 add $1, %ax
 | 
			
		||||
    1       1   1002 mov %ax, 2000
 | 
			
		||||
    1       0   1003 sub  $1, %bx
 | 
			
		||||
    1       0   1004 test $0, %bx
 | 
			
		||||
    1       0   1005 jgt .top
 | 
			
		||||
    1       0   1006 halt
 | 
			
		||||
    1       1   ----- Halt;Switch -----  ----- Halt;Switch -----
 | 
			
		||||
    1       1                            1000 mov 2000, %ax
 | 
			
		||||
    1       1                            1001 add $1, %ax
 | 
			
		||||
    2       1                            1002 mov %ax, 2000
 | 
			
		||||
    2       0                            1003 sub  $1, %bx
 | 
			
		||||
    2       0                            1004 test $0, %bx
 | 
			
		||||
    2       0                            1005 jgt .top
 | 
			
		||||
    2       0                            1006 halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
多线程存在  race condition 的例子 looping-race-nolock.s 在引入中断后,会产生race condition.
 | 
			
		||||
```
 | 
			
		||||
$ ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -i 2
 | 
			
		||||
 | 
			
		||||
 2000          Thread 0                Thread 1
 | 
			
		||||
    ?
 | 
			
		||||
    ?   1000 mov 2000, %ax
 | 
			
		||||
    ?   1001 add $1, %ax
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?                            1000 mov 2000, %ax
 | 
			
		||||
    ?                            1001 add $1, %ax
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?   1002 mov %ax, 2000
 | 
			
		||||
    ?   1003 sub  $1, %bx
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?                            1002 mov %ax, 2000
 | 
			
		||||
    ?                            1003 sub  $1, %bx
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?   1004 test $0, %bx
 | 
			
		||||
    ?   1005 jgt .top
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?                            1004 test $0, %bx
 | 
			
		||||
    ?                            1005 jgt .top
 | 
			
		||||
    ?   ------ Interrupt ------  ------ Interrupt ------
 | 
			
		||||
    ?   1006 halt
 | 
			
		||||
    ?   ----- Halt;Switch -----  ----- Halt;Switch -----
 | 
			
		||||
    ?                            1006 halt
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								related_info/lab7/race-condition/loop.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								related_info/lab7/race-condition/loop.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
.main
 | 
			
		||||
.top
 | 
			
		||||
sub  $1,%dx
 | 
			
		||||
test $0,%dx     
 | 
			
		||||
jgte .top         
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										15
									
								
								related_info/lab7/race-condition/looping-race-nolock.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								related_info/lab7/race-condition/looping-race-nolock.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# assumes %bx has loop count in it
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top	
 | 
			
		||||
# critical section
 | 
			
		||||
mov 2000, %ax  # get the value at the address
 | 
			
		||||
add $1, %ax    # increment it
 | 
			
		||||
mov %ax, 2000  # store it back
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										6
									
								
								related_info/lab7/race-condition/simple-race.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								related_info/lab7/race-condition/simple-race.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
.main
 | 
			
		||||
# this is a critical section
 | 
			
		||||
mov 2000(%bx), %ax   # get the value at the address
 | 
			
		||||
add $1, %ax          # increment it
 | 
			
		||||
mov %ax, 2000(%bx)   # store it back
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										7
									
								
								related_info/lab7/race-condition/test.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								related_info/lab7/race-condition/test.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
.main
 | 
			
		||||
mov  $9,%dx
 | 
			
		||||
.top
 | 
			
		||||
sub  $1,%dx
 | 
			
		||||
test $0,%dx     
 | 
			
		||||
jgte .top         
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										13
									
								
								related_info/lab7/race-condition/wait-for-me.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								related_info/lab7/race-condition/wait-for-me.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
.main
 | 
			
		||||
test $1, %ax     # ax should be 1 (signaller) or 0 (waiter)
 | 
			
		||||
je .signaller
 | 
			
		||||
 | 
			
		||||
.waiter	
 | 
			
		||||
mov  2000, %cx
 | 
			
		||||
test $1, %cx
 | 
			
		||||
jne .waiter
 | 
			
		||||
halt
 | 
			
		||||
 | 
			
		||||
.signaller
 | 
			
		||||
mov  $1, 2000
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										989
									
								
								related_info/lab7/race-condition/x86.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										989
									
								
								related_info/lab7/race-condition/x86.py
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,989 @@
 | 
			
		||||
#! /usr/bin/env python
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import time
 | 
			
		||||
import random
 | 
			
		||||
from optparse import OptionParser
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# HELPER
 | 
			
		||||
#
 | 
			
		||||
def dospace(howmuch):
 | 
			
		||||
    for i in range(howmuch):
 | 
			
		||||
        print '%24s' % ' ',
 | 
			
		||||
 | 
			
		||||
# useful instead of assert
 | 
			
		||||
def zassert(cond, str):
 | 
			
		||||
    if cond == False:
 | 
			
		||||
        print 'ABORT::', str
 | 
			
		||||
        exit(1)
 | 
			
		||||
    return
 | 
			
		||||
 | 
			
		||||
class cpu:
 | 
			
		||||
    #
 | 
			
		||||
    # INIT: how much memory?
 | 
			
		||||
    #
 | 
			
		||||
    def __init__(self, memory, memtrace, regtrace, cctrace, compute, verbose):
 | 
			
		||||
        #
 | 
			
		||||
        # CONSTANTS
 | 
			
		||||
        #
 | 
			
		||||
        
 | 
			
		||||
        # conditions
 | 
			
		||||
        self.COND_GT        = 0
 | 
			
		||||
        self.COND_GTE       = 1
 | 
			
		||||
        self.COND_LT        = 2
 | 
			
		||||
        self.COND_LTE       = 3
 | 
			
		||||
        self.COND_EQ        = 4
 | 
			
		||||
        self.COND_NEQ       = 5
 | 
			
		||||
 | 
			
		||||
        # registers in system
 | 
			
		||||
        self.REG_ZERO       = 0
 | 
			
		||||
        self.REG_AX         = 1
 | 
			
		||||
        self.REG_BX         = 2
 | 
			
		||||
        self.REG_CX         = 3
 | 
			
		||||
        self.REG_DX         = 4
 | 
			
		||||
        self.REG_SP         = 5
 | 
			
		||||
        self.REG_BP         = 6
 | 
			
		||||
 | 
			
		||||
        # system memory: in KB
 | 
			
		||||
        self.max_memory     = memory * 1024
 | 
			
		||||
 | 
			
		||||
        # which memory addrs and registers to trace?
 | 
			
		||||
        self.memtrace       = memtrace
 | 
			
		||||
        self.regtrace       = regtrace
 | 
			
		||||
        self.cctrace        = cctrace
 | 
			
		||||
        self.compute        = compute
 | 
			
		||||
        self.verbose        = verbose
 | 
			
		||||
 | 
			
		||||
        self.PC             = 0
 | 
			
		||||
        self.registers      = {}
 | 
			
		||||
        self.conditions     = {}
 | 
			
		||||
        self.labels         = {}
 | 
			
		||||
        self.vars           = {}
 | 
			
		||||
        self.memory         = {}
 | 
			
		||||
        self.pmemory        = {}  # for printable version of what's in memory (instructions)
 | 
			
		||||
 | 
			
		||||
        self.condlist       = [self.COND_GTE, self.COND_GT, self.COND_LTE, self.COND_LT, self.COND_NEQ, self.COND_EQ]
 | 
			
		||||
        self.regnums        = [self.REG_ZERO, self.REG_AX,  self.REG_BX,   self.REG_CX,  self.REG_DX,   self.REG_SP,  self.REG_BP]
 | 
			
		||||
 | 
			
		||||
        self.regnames         = {}
 | 
			
		||||
        self.regnames['zero'] = self.REG_ZERO # hidden zero-valued register
 | 
			
		||||
        self.regnames['ax']   = self.REG_AX
 | 
			
		||||
        self.regnames['bx']   = self.REG_BX
 | 
			
		||||
        self.regnames['cx']   = self.REG_CX
 | 
			
		||||
        self.regnames['dx']   = self.REG_DX
 | 
			
		||||
        self.regnames['sp']   = self.REG_SP
 | 
			
		||||
        self.regnames['bp']   = self.REG_BP
 | 
			
		||||
 | 
			
		||||
        tmplist = []
 | 
			
		||||
        for r in self.regtrace:
 | 
			
		||||
            zassert(r in self.regnames, 'Register %s cannot be traced because it does not exist' % r)
 | 
			
		||||
            tmplist.append(self.regnames[r])
 | 
			
		||||
        self.regtrace = tmplist
 | 
			
		||||
 | 
			
		||||
        self.init_memory()
 | 
			
		||||
        self.init_registers()
 | 
			
		||||
        self.init_condition_codes()
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # BEFORE MACHINE RUNS
 | 
			
		||||
    #
 | 
			
		||||
    def init_condition_codes(self):
 | 
			
		||||
        for c in self.condlist:
 | 
			
		||||
            self.conditions[c] = False
 | 
			
		||||
 | 
			
		||||
    def init_memory(self):
 | 
			
		||||
        for i in range(self.max_memory):
 | 
			
		||||
            self.memory[i] = 0
 | 
			
		||||
 | 
			
		||||
    def init_registers(self):
 | 
			
		||||
        for i in self.regnums:
 | 
			
		||||
            self.registers[i] = 0
 | 
			
		||||
 | 
			
		||||
    def dump_memory(self):
 | 
			
		||||
        print 'MEMORY DUMP'
 | 
			
		||||
        for i in range(self.max_memory):
 | 
			
		||||
            if i not in self.pmemory and i in self.memory and self.memory[i] != 0:
 | 
			
		||||
                print '  m[%d]' % i, self.memory[i]
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # INFORMING ABOUT THE HARDWARE
 | 
			
		||||
    #
 | 
			
		||||
    def get_regnum(self, name):
 | 
			
		||||
        assert(name in self.regnames)
 | 
			
		||||
        return self.regnames[name]
 | 
			
		||||
 | 
			
		||||
    def get_regname(self, num):
 | 
			
		||||
        assert(num in self.regnums)
 | 
			
		||||
        for rname in self.regnames:
 | 
			
		||||
            if self.regnames[rname] == num:
 | 
			
		||||
                return rname
 | 
			
		||||
        return ''
 | 
			
		||||
    
 | 
			
		||||
    def get_regnums(self):
 | 
			
		||||
        return self.regnums
 | 
			
		||||
 | 
			
		||||
    def get_condlist(self):
 | 
			
		||||
        return self.condlist
 | 
			
		||||
 | 
			
		||||
    def get_reg(self, reg):
 | 
			
		||||
        assert(reg in self.regnums)
 | 
			
		||||
        return self.registers[reg]
 | 
			
		||||
 | 
			
		||||
    def get_cond(self, cond):
 | 
			
		||||
        assert(cond in self.condlist)
 | 
			
		||||
        return self.conditions[cond]
 | 
			
		||||
 | 
			
		||||
    def get_pc(self):
 | 
			
		||||
        return self.PC
 | 
			
		||||
        
 | 
			
		||||
    def set_reg(self, reg, value):
 | 
			
		||||
        assert(reg in self.regnums)
 | 
			
		||||
        self.registers[reg] = value
 | 
			
		||||
 | 
			
		||||
    def set_cond(self, cond, value):
 | 
			
		||||
        assert(cond in self.condlist)
 | 
			
		||||
        self.conditions[cond] = value
 | 
			
		||||
 | 
			
		||||
    def set_pc(self, pc):
 | 
			
		||||
        self.PC = pc
 | 
			
		||||
        
 | 
			
		||||
    #
 | 
			
		||||
    # INSTRUCTIONS
 | 
			
		||||
    #
 | 
			
		||||
    def halt(self):
 | 
			
		||||
        return -1
 | 
			
		||||
 | 
			
		||||
    def iyield(self):
 | 
			
		||||
        return -2
 | 
			
		||||
 | 
			
		||||
    def nop(self):
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def rdump(self):
 | 
			
		||||
        print 'REGISTERS::',
 | 
			
		||||
        print 'ax:', self.registers[self.REG_AX], 
 | 
			
		||||
        print 'bx:', self.registers[self.REG_BX], 
 | 
			
		||||
        print 'cx:', self.registers[self.REG_CX], 
 | 
			
		||||
        print 'dx:', self.registers[self.REG_DX],
 | 
			
		||||
 | 
			
		||||
    def mdump(self, index):
 | 
			
		||||
        print 'm[%d] ' % index, self.memory[index]
 | 
			
		||||
 | 
			
		||||
    def move_i_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] = src
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    # memory: value, register, register
 | 
			
		||||
    def move_i_to_m(self, src, value, reg1, reg2):
 | 
			
		||||
        tmp = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        self.memory[tmp] = src
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def move_m_to_r(self, value, reg1, reg2, dst):
 | 
			
		||||
        tmp = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        # print 'doing mov', 'val:', value, 'r1:', self.get_regname(reg1), self.registers[reg1], 'r2:', self.get_regname(reg2), self.registers[reg2], 'dst', self.get_regname(dst), 'tmp', tmp, 'reg[dst]', self.registers[dst], 'mem', self.memory[tmp]
 | 
			
		||||
        self.registers[dst] = self.memory[tmp] 
 | 
			
		||||
 | 
			
		||||
    def move_r_to_m(self, src, value, reg1, reg2):
 | 
			
		||||
        tmp = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        self.memory[tmp] = self.registers[src]
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def move_r_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] = self.registers[src]
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def add_i_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] += src
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def add_r_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] += self.registers[src]
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def sub_i_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] -= src
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def sub_r_to_r(self, src, dst):
 | 
			
		||||
        self.registers[dst] -= self.registers[src]
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # SUPPORT FOR LOCKS
 | 
			
		||||
    #
 | 
			
		||||
    def atomic_exchange(self, src, value, reg1, reg2):
 | 
			
		||||
        tmp                 = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        old                 = self.memory[tmp]
 | 
			
		||||
        self.memory[tmp]    = self.registers[src]
 | 
			
		||||
        self.registers[src] = old
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def fetchadd(self, src, value, reg1, reg2):
 | 
			
		||||
        tmp                 = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        old                 = self.memory[tmp]
 | 
			
		||||
        self.memory[tmp]    = self.memory[tmp] + self.registers[src] 
 | 
			
		||||
        self.registers[src] = old
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # TEST for conditions
 | 
			
		||||
    #
 | 
			
		||||
    def test_all(self, src, dst):
 | 
			
		||||
        self.init_condition_codes()
 | 
			
		||||
        if dst > src:
 | 
			
		||||
            self.conditions[self.COND_GT]  = True
 | 
			
		||||
        if dst >= src:
 | 
			
		||||
            self.conditions[self.COND_GTE] = True
 | 
			
		||||
        if dst < src:
 | 
			
		||||
            self.conditions[self.COND_LT]  = True
 | 
			
		||||
        if dst <= src:
 | 
			
		||||
            self.conditions[self.COND_LTE] = True
 | 
			
		||||
        if dst == src:
 | 
			
		||||
            self.conditions[self.COND_EQ]  = True
 | 
			
		||||
        if dst != src:
 | 
			
		||||
            self.conditions[self.COND_NEQ] = True
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def test_i_r(self, src, dst):
 | 
			
		||||
        self.init_condition_codes()
 | 
			
		||||
        return self.test_all(src, self.registers[dst])
 | 
			
		||||
 | 
			
		||||
    def test_r_i(self, src, dst):
 | 
			
		||||
        self.init_condition_codes()
 | 
			
		||||
        return self.test_all(self.registers[src], dst)
 | 
			
		||||
 | 
			
		||||
    def test_r_r(self, src, dst):
 | 
			
		||||
        self.init_condition_codes()
 | 
			
		||||
        return self.test_all(self.registers[src], self.registers[dst])
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # JUMPS
 | 
			
		||||
    #
 | 
			
		||||
    def jump(self, targ):
 | 
			
		||||
        self.PC = targ  
 | 
			
		||||
        return 0
 | 
			
		||||
    
 | 
			
		||||
    def jump_notequal(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_NEQ] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def jump_equal(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_EQ] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def jump_lessthan(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_LT] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def jump_lessthanorequal(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_LTE] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def jump_greaterthan(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_GT] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def jump_greaterthanorequal(self, targ):
 | 
			
		||||
        if self.conditions[self.COND_GTE] == True:
 | 
			
		||||
            self.PC = targ
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # CALL and RETURN
 | 
			
		||||
    #
 | 
			
		||||
    def call(self, targ):
 | 
			
		||||
        self.registers[self.REG_SP] -= 4
 | 
			
		||||
        self.memory[self.registers[self.REG_SP]] = self.PC 
 | 
			
		||||
        self.PC = targ
 | 
			
		||||
 | 
			
		||||
    def ret(self):
 | 
			
		||||
        self.PC = self.memory[self.registers[self.REG_SP]]
 | 
			
		||||
        self.registers[self.REG_SP] += 4
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # STACK and related
 | 
			
		||||
    #
 | 
			
		||||
    def push_r(self, reg):
 | 
			
		||||
        self.registers[self.REG_SP] -= 4
 | 
			
		||||
        self.memory[self.registers[self.REG_SP]] = self.registers[reg]
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def push_m(self, value, reg1, reg2):
 | 
			
		||||
        # print 'push_m', value, reg1, reg2
 | 
			
		||||
        self.registers[self.REG_SP] -= 4
 | 
			
		||||
        tmp = value + self.registers[reg1] + self.registers[reg2]
 | 
			
		||||
        # push address onto stack, not memory value itself
 | 
			
		||||
        self.memory[self.registers[self.REG_SP]] = tmp
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    def pop(self):
 | 
			
		||||
        self.registers[self.REG_SP] += 4
 | 
			
		||||
 | 
			
		||||
    def pop_r(self, dst):
 | 
			
		||||
        self.registers[dst] = self.registers[self.REG_SP]
 | 
			
		||||
        self.registers[self.REG_SP] += 4
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # HELPER func for getarg
 | 
			
		||||
    #
 | 
			
		||||
    def register_translate(self, r):
 | 
			
		||||
        if r in self.regnames:
 | 
			
		||||
            return self.regnames[r]
 | 
			
		||||
        zassert(False, 'Register %s is not a valid register' % r)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # HELPER in parsing mov (quite primitive) and other ops
 | 
			
		||||
    # returns: (value, type)
 | 
			
		||||
    # where type is (TYPE_REGISTER, TYPE_IMMEDIATE, TYPE_MEMORY)
 | 
			
		||||
    # 
 | 
			
		||||
    # FORMATS
 | 
			
		||||
    #    %ax           - register
 | 
			
		||||
    #    $10           - immediate
 | 
			
		||||
    #    10            - direct memory
 | 
			
		||||
    #    10(%ax)       - memory + reg indirect
 | 
			
		||||
    #    10(%ax,%bx)   - memory + 2 reg indirect
 | 
			
		||||
    #    10(%ax,%bx,4) - XXX (not handled)
 | 
			
		||||
    #
 | 
			
		||||
    def getarg(self, arg):
 | 
			
		||||
        tmp1 = arg.replace(',', '')
 | 
			
		||||
        tmp  = tmp1.replace(' \t', '')
 | 
			
		||||
 | 
			
		||||
        if tmp[0] == '$':
 | 
			
		||||
            zassert(len(tmp) == 2, 'correct form is $number (not %s)' % tmp)
 | 
			
		||||
            value = tmp.split('$')[1]
 | 
			
		||||
            zassert(value.isdigit(), 'value [%s] must be a digit' % value)
 | 
			
		||||
            return int(value), 'TYPE_IMMEDIATE'
 | 
			
		||||
        elif tmp[0] == '%':
 | 
			
		||||
            register = tmp.split('%')[1]
 | 
			
		||||
            return self.register_translate(register), 'TYPE_REGISTER'
 | 
			
		||||
        elif tmp[0] == '(':
 | 
			
		||||
            register = tmp.split('(')[1].split(')')[0].split('%')[1]
 | 
			
		||||
            return '%d,%d,%d' % (0, self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
        elif tmp[0] == '.':
 | 
			
		||||
            targ = tmp
 | 
			
		||||
            return targ, 'TYPE_LABEL'
 | 
			
		||||
        elif tmp[0].isalpha() and not tmp[0].isdigit():
 | 
			
		||||
            zassert(tmp in self.vars, 'Variable %s is not declared' % tmp)
 | 
			
		||||
            # print '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
            return '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
        elif tmp[0].isdigit() or tmp[0] == '-':
 | 
			
		||||
            # MOST GENERAL CASE: number(reg,reg) or number(reg)
 | 
			
		||||
            # we ignore the common x86 number(reg,reg,constant) for now
 | 
			
		||||
            neg = 1
 | 
			
		||||
            if tmp[0] == '-':
 | 
			
		||||
                tmp = tmp[1:]
 | 
			
		||||
                neg = -1
 | 
			
		||||
            s = tmp.split('(')
 | 
			
		||||
            if len(s) == 1:
 | 
			
		||||
                value = neg * int(tmp)
 | 
			
		||||
                # print '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
                return '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
            elif len(s) == 2:
 | 
			
		||||
                value = neg * int(s[0])
 | 
			
		||||
                t = s[1].split(')')[0].split(',')
 | 
			
		||||
                if len(t) == 1:
 | 
			
		||||
                    register = t[0].split('%')[1]
 | 
			
		||||
                    # print '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
                    return '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
 | 
			
		||||
                elif len(t) == 2:
 | 
			
		||||
                    register1 = t[0].split('%')[1]
 | 
			
		||||
                    register2 = t[1].split('%')[1]
 | 
			
		||||
                    # print '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY'
 | 
			
		||||
                    return '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY'
 | 
			
		||||
            else:
 | 
			
		||||
                print 'mov: bad argument [%s]' % tmp
 | 
			
		||||
                exit(1)
 | 
			
		||||
                return
 | 
			
		||||
        zassert(True, 'mov: bad argument [%s]' % arg)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # LOAD a program into memory
 | 
			
		||||
    # make it ready to execute
 | 
			
		||||
    #
 | 
			
		||||
    def load(self, infile, loadaddr):
 | 
			
		||||
        pc   = int(loadaddr)
 | 
			
		||||
        fd   = open(infile)
 | 
			
		||||
 | 
			
		||||
        bpc  = loadaddr
 | 
			
		||||
        data = 100
 | 
			
		||||
 | 
			
		||||
        for line in fd:
 | 
			
		||||
            cline = line.rstrip()
 | 
			
		||||
            # print 'PASS 1', cline
 | 
			
		||||
 | 
			
		||||
            # remove everything after the comment marker
 | 
			
		||||
            ctmp = cline.split('#')
 | 
			
		||||
            assert(len(ctmp) == 1 or len(ctmp) == 2)
 | 
			
		||||
            if len(ctmp) == 2:
 | 
			
		||||
                cline = ctmp[0]
 | 
			
		||||
 | 
			
		||||
            # remove empty lines, and split line by spaces
 | 
			
		||||
            tmp = cline.split()
 | 
			
		||||
            if len(tmp) == 0:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            # only pay attention to labels and variables
 | 
			
		||||
            if tmp[0] == '.var':
 | 
			
		||||
                assert(len(tmp) == 2)
 | 
			
		||||
                assert(tmp[0] not in self.vars)
 | 
			
		||||
                self.vars[tmp[1]] = data
 | 
			
		||||
                data += 4
 | 
			
		||||
                zassert(data < bpc, 'Load address overrun by static data')
 | 
			
		||||
                if self.verbose: print 'ASSIGN VAR', tmp[0], "-->", tmp[1], self.vars[tmp[1]]
 | 
			
		||||
            elif tmp[0][0] == '.':
 | 
			
		||||
                assert(len(tmp) == 1)
 | 
			
		||||
                self.labels[tmp[0]] = int(pc)
 | 
			
		||||
                if self.verbose: print 'ASSIGN LABEL', tmp[0], "-->", pc
 | 
			
		||||
            else:
 | 
			
		||||
                pc += 1
 | 
			
		||||
        fd.close()
 | 
			
		||||
 | 
			
		||||
        if self.verbose: print ''
 | 
			
		||||
 | 
			
		||||
        # second pass: do everything else
 | 
			
		||||
        pc = int(loadaddr)
 | 
			
		||||
        fd = open(infile)
 | 
			
		||||
        for line in fd:
 | 
			
		||||
            cline = line.rstrip()
 | 
			
		||||
            # print 'PASS 2', cline
 | 
			
		||||
 | 
			
		||||
            # remove everything after the comment marker
 | 
			
		||||
            ctmp = cline.split('#')
 | 
			
		||||
            assert(len(ctmp) == 1 or len(ctmp) == 2)
 | 
			
		||||
            if len(ctmp) == 2:
 | 
			
		||||
                cline = ctmp[0]
 | 
			
		||||
 | 
			
		||||
            # remove empty lines, and split line by spaces
 | 
			
		||||
            tmp = cline.split()
 | 
			
		||||
            if len(tmp) == 0:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            # skip labels: all else must be instructions
 | 
			
		||||
            if cline[0] != '.':
 | 
			
		||||
                tmp              = cline.split(None, 1)
 | 
			
		||||
                opcode           = tmp[0]
 | 
			
		||||
                self.pmemory[pc] = cline.strip()
 | 
			
		||||
 | 
			
		||||
                # MAIN OPCODE LOOP
 | 
			
		||||
                if opcode == 'mov':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'mov: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    # print 'MOV', src, stype, dst, dtype
 | 
			
		||||
                    if stype == 'TYPE_MEMORY' and dtype == 'TYPE_MEMORY':
 | 
			
		||||
                        print 'bad mov: two memory arguments'
 | 
			
		||||
                        exit(1)
 | 
			
		||||
                    elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_IMMEDIATE':
 | 
			
		||||
                        print 'bad mov: two immediate arguments'
 | 
			
		||||
                        exit(1)
 | 
			
		||||
                    elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc]  = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc]  = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_MEMORY'    and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        tmp = src.split(',')
 | 
			
		||||
                        assert(len(tmp) == 3)
 | 
			
		||||
                        self.memory[pc] = 'self.move_m_to_r(%d, %d, %d, %d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), dst)
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER'  and dtype == 'TYPE_MEMORY':
 | 
			
		||||
                        tmp = dst.split(',')
 | 
			
		||||
                        assert(len(tmp) == 3)
 | 
			
		||||
                        self.memory[pc] = 'self.move_r_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER'  and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.move_r_to_r(%d, %d)' % (src, dst)
 | 
			
		||||
                    elif stype == 'TYPE_IMMEDIATE'  and dtype == 'TYPE_MEMORY':
 | 
			
		||||
                        tmp = dst.split(',')
 | 
			
		||||
                        assert(len(tmp) == 3)
 | 
			
		||||
                        self.memory[pc] = 'self.move_i_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'malformed mov instruction')
 | 
			
		||||
                elif opcode == 'pop':
 | 
			
		||||
                    if len(tmp) == 1:
 | 
			
		||||
                        self.memory[pc] = 'self.pop()'
 | 
			
		||||
                    elif len(tmp) == 2:
 | 
			
		||||
                        arg = tmp[1].strip()
 | 
			
		||||
                        (dst, dtype) = self.getarg(arg)
 | 
			
		||||
                        zassert(dtype == 'TYPE_REGISTER', 'Can only pop into a register')
 | 
			
		||||
                        self.memory[pc] = 'self.pop_r(%d)' % dst
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'pop instruction must take zero/one args')
 | 
			
		||||
                elif opcode == 'push':
 | 
			
		||||
                    (src, stype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    if stype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.push_r(%d)' % (int(src))
 | 
			
		||||
                    elif stype == 'TYPE_MEMORY':
 | 
			
		||||
                        tmp = src.split(',')
 | 
			
		||||
                        assert(len(tmp) == 3)
 | 
			
		||||
                        self.memory[pc] = 'self.push_m(%d,%d,%d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]))
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'Cannot push anything but registers')
 | 
			
		||||
                elif opcode == 'call':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    if ttype == 'TYPE_LABEL':
 | 
			
		||||
                        self.memory[pc] = 'self.call(%d)' % (int(self.labels[targ]))
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'Cannot call anything but a label')
 | 
			
		||||
                elif opcode == 'ret':
 | 
			
		||||
                    assert(len(tmp) == 1)
 | 
			
		||||
                    self.memory[pc] = 'self.ret()'
 | 
			
		||||
                elif opcode == 'add':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'add: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.add_i_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.add_r_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'malformed usage of add instruction')
 | 
			
		||||
                elif opcode == 'sub':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'sub: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.sub_i_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.sub_r_to_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'malformed usage of sub instruction')
 | 
			
		||||
                elif opcode == 'fetchadd':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'fetchadd: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    tmp = dst.split(',')
 | 
			
		||||
                    assert(len(tmp) == 3)
 | 
			
		||||
                    if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
 | 
			
		||||
                        self.memory[pc] = 'self.fetchadd(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'poorly specified fetch and add')
 | 
			
		||||
                elif opcode == 'xchg':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'xchg: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    tmp = dst.split(',')
 | 
			
		||||
                    assert(len(tmp) == 3)
 | 
			
		||||
                    if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
 | 
			
		||||
                        self.memory[pc] = 'self.atomic_exchange(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'poorly specified atomic exchange')
 | 
			
		||||
                elif opcode == 'test':
 | 
			
		||||
                    rtmp = tmp[1].split(',', 1)
 | 
			
		||||
                    zassert(len(tmp) == 2 and len(rtmp) == 2, 'test: needs two args, separated by commas [%s]' % cline)
 | 
			
		||||
                    arg1 = rtmp[0].strip()
 | 
			
		||||
                    arg2 = rtmp[1].strip()
 | 
			
		||||
                    (src, stype) = self.getarg(arg1)
 | 
			
		||||
                    (dst, dtype) = self.getarg(arg2)
 | 
			
		||||
                    if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.test_i_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
 | 
			
		||||
                        self.memory[pc] = 'self.test_r_r(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_IMMEDIATE':
 | 
			
		||||
                        self.memory[pc] = 'self.test_r_i(%d, %d)' % (int(src), dst)
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(False, 'malformed usage of test instruction')
 | 
			
		||||
                elif opcode == 'j':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump(%d)' % int(self.labels[targ])
 | 
			
		||||
                elif opcode == 'jne':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_notequal(%d)' % int(self.labels[targ])
 | 
			
		||||
                elif opcode == 'je':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_equal(%d)' % self.labels[targ]
 | 
			
		||||
                elif opcode == 'jlt':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_lessthan(%d)' % int(self.labels[targ])
 | 
			
		||||
                elif opcode == 'jlte':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_lessthanorequal(%s)' % self.labels[targ]
 | 
			
		||||
                elif opcode == 'jgt':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_greaterthan(%d)' % int(self.labels[targ])
 | 
			
		||||
                elif opcode == 'jgte':
 | 
			
		||||
                    (targ, ttype) = self.getarg(tmp[1].strip())
 | 
			
		||||
                    zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
 | 
			
		||||
                    self.memory[pc] = 'self.jump_greaterthanorequal(%s)' % self.labels[targ]
 | 
			
		||||
                elif opcode == 'nop':
 | 
			
		||||
                    self.memory[pc] = 'self.nop()'
 | 
			
		||||
                elif opcode == 'halt':
 | 
			
		||||
                    self.memory[pc] = 'self.halt()'
 | 
			
		||||
                elif opcode == 'yield':
 | 
			
		||||
                    self.memory[pc] = 'self.iyield()'
 | 
			
		||||
                elif opcode == 'rdump':
 | 
			
		||||
                    self.memory[pc] = 'self.rdump()'
 | 
			
		||||
                elif opcode == 'mdump':
 | 
			
		||||
                    self.memory[pc] = 'self.mdump(%s)' % tmp[1]
 | 
			
		||||
                else:
 | 
			
		||||
                    print 'illegal opcode: ', opcode
 | 
			
		||||
                    exit(1)
 | 
			
		||||
 | 
			
		||||
                if self.verbose: print 'pc:%d LOADING %20s --> %s' % (pc, self.pmemory[pc], self.memory[pc])
 | 
			
		||||
                
 | 
			
		||||
                # INCREMENT PC for loader
 | 
			
		||||
                pc += 1
 | 
			
		||||
        # END: loop over file
 | 
			
		||||
        fd.close()
 | 
			
		||||
        if self.verbose: print ''
 | 
			
		||||
        return
 | 
			
		||||
    # END: load
 | 
			
		||||
 | 
			
		||||
    def print_headers(self, procs):
 | 
			
		||||
        # print some headers
 | 
			
		||||
        if len(self.memtrace) > 0:
 | 
			
		||||
            for m in self.memtrace:
 | 
			
		||||
                if m[0].isdigit():
 | 
			
		||||
                    print '%5d' % int(m),
 | 
			
		||||
                else:
 | 
			
		||||
                    zassert(m in self.vars, 'Traced variable %s not declared' % m)
 | 
			
		||||
                    print '%5s' % m,
 | 
			
		||||
            print ' ',
 | 
			
		||||
        if len(self.regtrace) > 0:
 | 
			
		||||
            for r in self.regtrace:
 | 
			
		||||
                print '%5s' % self.get_regname(r),
 | 
			
		||||
            print ' ',
 | 
			
		||||
        if cctrace == True:
 | 
			
		||||
            print '>= >  <= <  != ==', 
 | 
			
		||||
 | 
			
		||||
        # and per thread
 | 
			
		||||
        for i in range(procs.getnum()):
 | 
			
		||||
            print '       Thread %d        ' % i,
 | 
			
		||||
        print ''
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def print_trace(self, newline):
 | 
			
		||||
        if len(self.memtrace) > 0:
 | 
			
		||||
            for m in self.memtrace:
 | 
			
		||||
                if self.compute:
 | 
			
		||||
                    if m[0].isdigit():
 | 
			
		||||
                        print '%5d' % self.memory[int(m)],
 | 
			
		||||
                    else:
 | 
			
		||||
                        zassert(m in self.vars, 'Traced variable %s not declared' % m)
 | 
			
		||||
                        print '%5d' % self.memory[self.vars[m]],
 | 
			
		||||
                else:
 | 
			
		||||
                    print '%5s' % '?',
 | 
			
		||||
            print ' ',
 | 
			
		||||
        if len(self.regtrace) > 0:
 | 
			
		||||
            for r in self.regtrace:
 | 
			
		||||
                if self.compute:
 | 
			
		||||
                    print '%5d' % self.registers[r],
 | 
			
		||||
                else:
 | 
			
		||||
                    print '%5s' % '?',
 | 
			
		||||
            print ' ',
 | 
			
		||||
        if cctrace == True:
 | 
			
		||||
            for c in self.condlist:
 | 
			
		||||
                if self.compute:
 | 
			
		||||
                    if self.conditions[c]:
 | 
			
		||||
                        print '1 ',
 | 
			
		||||
                    else:
 | 
			
		||||
                        print '0 ',
 | 
			
		||||
                else:
 | 
			
		||||
                    print '? ',
 | 
			
		||||
        if (len(self.memtrace) > 0 or len(self.regtrace) > 0 or cctrace == True) and newline == True:
 | 
			
		||||
            print ''
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def setint(self, intfreq, intrand):
 | 
			
		||||
        if intrand == False:
 | 
			
		||||
            return intfreq
 | 
			
		||||
        return int(random.random() * intfreq) + 1
 | 
			
		||||
 | 
			
		||||
    def run(self, procs, intfreq, intrand):
 | 
			
		||||
        # hw init: cc's, interrupt frequency, etc.
 | 
			
		||||
        interrupt = self.setint(intfreq, intrand)
 | 
			
		||||
        icount    = 0
 | 
			
		||||
 | 
			
		||||
        self.print_headers(procs)
 | 
			
		||||
        self.print_trace(True)
 | 
			
		||||
        
 | 
			
		||||
        while True:
 | 
			
		||||
            # need thread ID of current process
 | 
			
		||||
            tid = procs.getcurr().gettid()
 | 
			
		||||
 | 
			
		||||
            # FETCH
 | 
			
		||||
            prevPC       = self.PC
 | 
			
		||||
            instruction  = self.memory[self.PC]
 | 
			
		||||
            self.PC     += 1
 | 
			
		||||
 | 
			
		||||
            # DECODE and EXECUTE
 | 
			
		||||
            # key: self.PC may be changed during eval; thus MUST be incremented BEFORE eval
 | 
			
		||||
            rc = eval(instruction)
 | 
			
		||||
 | 
			
		||||
            # tracing details: ALWAYS AFTER EXECUTION OF INSTRUCTION
 | 
			
		||||
            self.print_trace(False)
 | 
			
		||||
 | 
			
		||||
            # output: thread-proportional spacing followed by PC and instruction
 | 
			
		||||
            dospace(tid)
 | 
			
		||||
            print prevPC, self.pmemory[prevPC]
 | 
			
		||||
            icount += 1
 | 
			
		||||
 | 
			
		||||
            # halt instruction issued
 | 
			
		||||
            if rc == -1:
 | 
			
		||||
                procs.done()
 | 
			
		||||
                if procs.numdone() == procs.getnum():
 | 
			
		||||
                    return icount
 | 
			
		||||
                procs.next()
 | 
			
		||||
                procs.restore()
 | 
			
		||||
 | 
			
		||||
                self.print_trace(False)
 | 
			
		||||
                for i in range(procs.getnum()):
 | 
			
		||||
                    print '----- Halt;Switch ----- ',
 | 
			
		||||
                print ''
 | 
			
		||||
 | 
			
		||||
            # do interrupt processing
 | 
			
		||||
            interrupt -= 1
 | 
			
		||||
            if interrupt == 0 or rc == -2:
 | 
			
		||||
                interrupt = self.setint(intfreq, intrand)
 | 
			
		||||
                procs.save()
 | 
			
		||||
                procs.next()
 | 
			
		||||
                procs.restore()
 | 
			
		||||
 | 
			
		||||
                self.print_trace(False)
 | 
			
		||||
                for i in range(procs.getnum()):
 | 
			
		||||
                    print '------ Interrupt ------ ',
 | 
			
		||||
                print ''
 | 
			
		||||
        # END: while
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
# 
 | 
			
		||||
# END: class cpu
 | 
			
		||||
# 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# PROCESS LIST class
 | 
			
		||||
#
 | 
			
		||||
class proclist:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.plist  = []
 | 
			
		||||
        self.curr   = 0
 | 
			
		||||
        self.active = 0
 | 
			
		||||
 | 
			
		||||
    def done(self):
 | 
			
		||||
        self.plist[self.curr].setdone()
 | 
			
		||||
        self.active -= 1
 | 
			
		||||
 | 
			
		||||
    def numdone(self):
 | 
			
		||||
        return len(self.plist) - self.active
 | 
			
		||||
 | 
			
		||||
    def getnum(self):
 | 
			
		||||
        return len(self.plist)
 | 
			
		||||
 | 
			
		||||
    def add(self, p):
 | 
			
		||||
        self.active += 1
 | 
			
		||||
        self.plist.append(p)
 | 
			
		||||
 | 
			
		||||
    def getcurr(self):
 | 
			
		||||
        return self.plist[self.curr]
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        self.plist[self.curr].save()
 | 
			
		||||
 | 
			
		||||
    def restore(self):
 | 
			
		||||
        self.plist[self.curr].restore()
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        for i in range(self.curr+1, len(self.plist)):
 | 
			
		||||
            if self.plist[i].isdone() == False:
 | 
			
		||||
                self.curr = i
 | 
			
		||||
                return
 | 
			
		||||
        for i in range(0, self.curr+1):
 | 
			
		||||
            if self.plist[i].isdone() == False:
 | 
			
		||||
                self.curr = i
 | 
			
		||||
                return
 | 
			
		||||
            
 | 
			
		||||
#
 | 
			
		||||
# PROCESS class
 | 
			
		||||
#
 | 
			
		||||
class process:
 | 
			
		||||
    def __init__(self, cpu, tid, pc, stackbottom, reginit):
 | 
			
		||||
        self.cpu   = cpu  # object reference
 | 
			
		||||
        self.tid   = tid
 | 
			
		||||
        self.pc    = pc
 | 
			
		||||
        self.regs  = {}
 | 
			
		||||
        self.cc    = {}
 | 
			
		||||
        self.done  = False
 | 
			
		||||
        self.stack = stackbottom
 | 
			
		||||
 | 
			
		||||
        # init regs: all 0 or specially set to something
 | 
			
		||||
        for r in self.cpu.get_regnums():
 | 
			
		||||
            self.regs[r] = 0
 | 
			
		||||
        if reginit != '':
 | 
			
		||||
            # form: ax=1,bx=2 (for some subset of registers)
 | 
			
		||||
            for r in reginit.split(':'):
 | 
			
		||||
                tmp = r.split('=')
 | 
			
		||||
                assert(len(tmp) == 2)
 | 
			
		||||
                self.regs[self.cpu.get_regnum(tmp[0])] = int(tmp[1])
 | 
			
		||||
 | 
			
		||||
        # init CCs
 | 
			
		||||
        for c in self.cpu.get_condlist():
 | 
			
		||||
            self.cc[c] = False
 | 
			
		||||
 | 
			
		||||
        # stack
 | 
			
		||||
        self.regs[self.cpu.get_regnum('sp')] = stackbottom
 | 
			
		||||
        # print 'REG', self.cpu.get_regnum('sp'), self.regs[self.cpu.get_regnum('sp')]
 | 
			
		||||
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def gettid(self):
 | 
			
		||||
        return self.tid
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        self.pc = self.cpu.get_pc()
 | 
			
		||||
        for c in self.cpu.get_condlist():
 | 
			
		||||
            self.cc[c] = self.cpu.get_cond(c)
 | 
			
		||||
        for r in self.cpu.get_regnums():
 | 
			
		||||
            self.regs[r] = self.cpu.get_reg(r)
 | 
			
		||||
 | 
			
		||||
    def restore(self):
 | 
			
		||||
        self.cpu.set_pc(self.pc)
 | 
			
		||||
        for c in self.cpu.get_condlist():
 | 
			
		||||
            self.cpu.set_cond(c, self.cc[c])
 | 
			
		||||
        for r in self.cpu.get_regnums():
 | 
			
		||||
            self.cpu.set_reg(r, self.regs[r])
 | 
			
		||||
 | 
			
		||||
    def setdone(self):
 | 
			
		||||
        self.done = True
 | 
			
		||||
 | 
			
		||||
    def isdone(self):
 | 
			
		||||
        return self.done == True
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# main program
 | 
			
		||||
#
 | 
			
		||||
parser = OptionParser()
 | 
			
		||||
parser.add_option('-s', '--seed',      default=0,          help='the random seed',                  action='store',      type='int',    dest='seed')
 | 
			
		||||
parser.add_option('-t', '--threads',   default=2,          help='number of threads',                action='store',      type='int',    dest='numthreads')
 | 
			
		||||
parser.add_option('-p', '--program',   default='',         help='source program (in .s)',           action='store',      type='string', dest='progfile')
 | 
			
		||||
parser.add_option('-i', '--interrupt', default=50,         help='interrupt frequency',              action='store',      type='int',    dest='intfreq')
 | 
			
		||||
parser.add_option('-r', '--randints',  default=False,      help='if interrupts are random',         action='store_true',                dest='intrand')
 | 
			
		||||
parser.add_option('-a', '--argv',      default='',
 | 
			
		||||
                  help='comma-separated per-thread args (e.g., ax=1,ax=2 sets thread 0 ax reg to 1 and thread 1 ax reg to 2); specify multiple regs per thread via colon-separated list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and just cx for thread 1)',
 | 
			
		||||
                  action='store',      type='string', dest='argv')
 | 
			
		||||
parser.add_option('-L', '--loadaddr',  default=1000,       help='address where to load code',       action='store',      type='int',    dest='loadaddr')
 | 
			
		||||
parser.add_option('-m', '--memsize',   default=128,        help='size of address space (KB)',       action='store',      type='int',    dest='memsize')
 | 
			
		||||
parser.add_option('-M', '--memtrace',  default='',         help='comma-separated list of addrs to trace (e.g., 20000,20001)', action='store',
 | 
			
		||||
                  type='string', dest='memtrace')
 | 
			
		||||
parser.add_option('-R', '--regtrace',  default='',         help='comma-separated list of regs to trace (e.g., ax,bx,cx,dx)',  action='store',
 | 
			
		||||
                  type='string', dest='regtrace')
 | 
			
		||||
parser.add_option('-C', '--cctrace',   default=False,      help='should we trace condition codes',  action='store_true', dest='cctrace')
 | 
			
		||||
parser.add_option('-S', '--printstats',default=False,      help='print some extra stats',           action='store_true', dest='printstats')
 | 
			
		||||
parser.add_option('-v', '--verbose',   default=False,      help='print some extra info',            action='store_true', dest='verbose')
 | 
			
		||||
parser.add_option('-c', '--compute',   default=False,      help='compute answers for me',           action='store_true', dest='solve')
 | 
			
		||||
(options, args) = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
print 'ARG seed',                options.seed
 | 
			
		||||
print 'ARG numthreads',          options.numthreads
 | 
			
		||||
print 'ARG program',             options.progfile
 | 
			
		||||
print 'ARG interrupt frequency', options.intfreq
 | 
			
		||||
print 'ARG interrupt randomness',options.intrand
 | 
			
		||||
print 'ARG argv',                options.argv
 | 
			
		||||
print 'ARG load address',        options.loadaddr
 | 
			
		||||
print 'ARG memsize',             options.memsize
 | 
			
		||||
print 'ARG memtrace',            options.memtrace
 | 
			
		||||
print 'ARG regtrace',            options.regtrace
 | 
			
		||||
print 'ARG cctrace',             options.cctrace
 | 
			
		||||
print 'ARG printstats',          options.printstats
 | 
			
		||||
print 'ARG verbose',             options.verbose
 | 
			
		||||
print ''
 | 
			
		||||
 | 
			
		||||
seed       = int(options.seed)
 | 
			
		||||
numthreads = int(options.numthreads)
 | 
			
		||||
intfreq    = int(options.intfreq)
 | 
			
		||||
zassert(intfreq > 0, 'Interrupt frequency must be greater than 0')
 | 
			
		||||
intrand    = int(options.intrand)
 | 
			
		||||
progfile   = options.progfile
 | 
			
		||||
zassert(progfile != '', 'Program file must be specified')
 | 
			
		||||
argv       = options.argv.split(',')
 | 
			
		||||
zassert(len(argv) == numthreads or len(argv) == 1, 'argv: must be one per-thread or just one set of values for all threads') 
 | 
			
		||||
 | 
			
		||||
loadaddr   = options.loadaddr
 | 
			
		||||
memsize    = options.memsize
 | 
			
		||||
 | 
			
		||||
memtrace   = []
 | 
			
		||||
if options.memtrace != '':
 | 
			
		||||
    for m in options.memtrace.split(','):
 | 
			
		||||
        memtrace.append(m)
 | 
			
		||||
 | 
			
		||||
regtrace   = []
 | 
			
		||||
if options.regtrace != '':
 | 
			
		||||
    for r in options.regtrace.split(','):
 | 
			
		||||
        regtrace.append(r)
 | 
			
		||||
 | 
			
		||||
cctrace    = options.cctrace
 | 
			
		||||
 | 
			
		||||
printstats = options.printstats
 | 
			
		||||
verbose    = options.verbose
 | 
			
		||||
        
 | 
			
		||||
#
 | 
			
		||||
# MAIN program
 | 
			
		||||
#
 | 
			
		||||
debug = False
 | 
			
		||||
debug = False
 | 
			
		||||
 | 
			
		||||
cpu = cpu(memsize, memtrace, regtrace, cctrace, options.solve, verbose)
 | 
			
		||||
 | 
			
		||||
# load a program
 | 
			
		||||
cpu.load(progfile, loadaddr)
 | 
			
		||||
 | 
			
		||||
# process list
 | 
			
		||||
procs = proclist()
 | 
			
		||||
pid   = 0
 | 
			
		||||
stack = memsize * 1000
 | 
			
		||||
for t in range(numthreads):
 | 
			
		||||
    if len(argv) > 1:
 | 
			
		||||
        arg = argv[pid]
 | 
			
		||||
    else:
 | 
			
		||||
        arg = argv[0]
 | 
			
		||||
    procs.add(process(cpu, pid, loadaddr, stack, arg))
 | 
			
		||||
    stack -= 1000
 | 
			
		||||
    pid += 1
 | 
			
		||||
 | 
			
		||||
# get first one ready!
 | 
			
		||||
procs.restore()
 | 
			
		||||
 | 
			
		||||
# run it
 | 
			
		||||
t1 = time.clock()
 | 
			
		||||
ic = cpu.run(procs, intfreq, intrand)
 | 
			
		||||
t2 = time.clock()
 | 
			
		||||
 | 
			
		||||
if printstats:
 | 
			
		||||
    print ''
 | 
			
		||||
    print 'STATS:: Instructions    %d' % ic
 | 
			
		||||
    print 'STATS:: Emulation Rate  %.2f kinst/sec' % (float(ic) / float(t2 - t1) / 1000.0)
 | 
			
		||||
 | 
			
		||||
# use this for profiling
 | 
			
		||||
# import cProfile
 | 
			
		||||
# cProfile.run('run()')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								related_info/lab7/software-hardware-locks/flag.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								related_info/lab7/software-hardware-locks/flag.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
.var flag
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov  flag, %ax      # get flag
 | 
			
		||||
test $0, %ax        # if we get 0 back: lock is free!
 | 
			
		||||
jne  .acquire       # if not, try again
 | 
			
		||||
mov  $1, flag       # store 1 into flag
 | 
			
		||||
 | 
			
		||||
# critical section
 | 
			
		||||
mov  count, %ax     # get the value at the address
 | 
			
		||||
add  $1, %ax        # increment it
 | 
			
		||||
mov  %ax, count     # store it back
 | 
			
		||||
 | 
			
		||||
# release lock
 | 
			
		||||
mov  $0, flag       # clear the flag now
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										53
									
								
								related_info/lab7/software-hardware-locks/peterson.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								related_info/lab7/software-hardware-locks/peterson.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
# array of 2 integers (each size 4 bytes)
 | 
			
		||||
# load address of flag into fx register
 | 
			
		||||
# access flag[] with 0(%fx,%index,4)
 | 
			
		||||
# where %index is a register holding 0 or 1
 | 
			
		||||
# index reg contains 0 -> flag[0], if 1->flag[1]
 | 
			
		||||
.var flag   2     
 | 
			
		||||
 | 
			
		||||
# global turn variable
 | 
			
		||||
.var turn
 | 
			
		||||
 | 
			
		||||
# global count
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
 | 
			
		||||
# put address of flag into fx
 | 
			
		||||
lea flag, %fx
 | 
			
		||||
 | 
			
		||||
# assume thread ID is in bx (0 or 1, scale by 4 to get proper flag address)
 | 
			
		||||
mov %bx, %cx   # bx: self, now copies to cx
 | 
			
		||||
neg %cx        # cx: - self
 | 
			
		||||
add $1, %cx    # cx: 1 - self
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov $1, 0(%fx,%bx,4)    # flag[self] = 1
 | 
			
		||||
mov %cx, turn           # turn       = 1 - self
 | 
			
		||||
 | 
			
		||||
.spin1
 | 
			
		||||
mov 0(%fx,%cx,4), %ax   # flag[1-self]
 | 
			
		||||
test $1, %ax            
 | 
			
		||||
jne .fini               # if flag[1-self] != 1, skip past loop to .fini
 | 
			
		||||
 | 
			
		||||
.spin2                  # just labeled for fun, not needed
 | 
			
		||||
mov turn, %ax
 | 
			
		||||
test %cx, %ax           # compare 'turn' and '1 - self'
 | 
			
		||||
je .spin1               # if turn==1-self, go back and start spin again
 | 
			
		||||
 | 
			
		||||
# fall out of spin
 | 
			
		||||
.fini
 | 
			
		||||
 | 
			
		||||
# do critical section now
 | 
			
		||||
mov count, %ax
 | 
			
		||||
add $1, %ax
 | 
			
		||||
mov %ax, count
 | 
			
		||||
 | 
			
		||||
.release
 | 
			
		||||
mov $0, 0(%fx,%bx,4)    # flag[self] = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# end case: make sure it's other's turn
 | 
			
		||||
mov %cx, turn           # turn       = 1 - self
 | 
			
		||||
halt
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								related_info/lab7/software-hardware-locks/test-and-set.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								related_info/lab7/software-hardware-locks/test-and-set.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
.var mutex
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top	
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov  $1, %ax        
 | 
			
		||||
xchg %ax, mutex     # atomic swap of 1 and mutex
 | 
			
		||||
test $0, %ax        # if we get 0 back: lock is free!
 | 
			
		||||
jne  .acquire       # if not, try again
 | 
			
		||||
 | 
			
		||||
# critical section
 | 
			
		||||
mov  count, %ax     # get the value at the address
 | 
			
		||||
add  $1, %ax        # increment it
 | 
			
		||||
mov  %ax, count     # store it back
 | 
			
		||||
 | 
			
		||||
# release lock
 | 
			
		||||
mov  $0, mutex
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
.var mutex
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top	
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov  mutex, %ax
 | 
			
		||||
test $0, %ax
 | 
			
		||||
jne .acquire
 | 
			
		||||
mov  $1, %ax        
 | 
			
		||||
xchg %ax, mutex     # atomic swap of 1 and mutex
 | 
			
		||||
test $0, %ax        # if we get 0 back: lock is free!
 | 
			
		||||
jne .acquire        # if not, try again
 | 
			
		||||
 | 
			
		||||
# critical section
 | 
			
		||||
mov  count, %ax     # get the value at the address
 | 
			
		||||
add  $1, %ax        # increment it
 | 
			
		||||
mov  %ax, count     # store it back
 | 
			
		||||
 | 
			
		||||
# release lock
 | 
			
		||||
mov  $0, mutex
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										30
									
								
								related_info/lab7/software-hardware-locks/ticket.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								related_info/lab7/software-hardware-locks/ticket.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
.var ticket
 | 
			
		||||
.var turn
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top	
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov $1, %ax
 | 
			
		||||
fetchadd %ax, ticket  # grab a ticket (keep it in dx)
 | 
			
		||||
.tryagain
 | 
			
		||||
mov turn, %cx         # check if it's your turn 
 | 
			
		||||
test %cx, %ax
 | 
			
		||||
jne .tryagain
 | 
			
		||||
 | 
			
		||||
# critical section
 | 
			
		||||
mov  count, %ax       # get the value at the address
 | 
			
		||||
add  $1, %ax          # increment it
 | 
			
		||||
mov  %ax, count       # store it back
 | 
			
		||||
 | 
			
		||||
# release lock
 | 
			
		||||
mov $1, %ax
 | 
			
		||||
fetchadd %ax, turn
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
							
								
								
									
										1186
									
								
								related_info/lab7/software-hardware-locks/x86.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1186
									
								
								related_info/lab7/software-hardware-locks/x86.py
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29
									
								
								related_info/lab7/software-hardware-locks/yield.s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								related_info/lab7/software-hardware-locks/yield.s
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
.var mutex
 | 
			
		||||
.var count
 | 
			
		||||
 | 
			
		||||
.main
 | 
			
		||||
.top	
 | 
			
		||||
 | 
			
		||||
.acquire
 | 
			
		||||
mov  $1, %ax        
 | 
			
		||||
xchg %ax, mutex     # atomic swap of 1 and mutex
 | 
			
		||||
test $0, %ax        # if we get 0 back: lock is free!
 | 
			
		||||
je .acquire_done    
 | 
			
		||||
yield               # if not, yield and try again
 | 
			
		||||
j .acquire
 | 
			
		||||
.acquire_done
 | 
			
		||||
 | 
			
		||||
# critical section
 | 
			
		||||
mov  count, %ax     # get the value at the address
 | 
			
		||||
add  $1, %ax        # increment it
 | 
			
		||||
mov  %ax, count     # store it back
 | 
			
		||||
 | 
			
		||||
# release lock
 | 
			
		||||
mov  $0, mutex
 | 
			
		||||
 | 
			
		||||
# see if we're still looping
 | 
			
		||||
sub  $1, %bx
 | 
			
		||||
test $0, %bx
 | 
			
		||||
jgt .top	
 | 
			
		||||
 | 
			
		||||
halt
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user