#encoding=utf-8
# reg file
reg = {
    'rax':0,
    'rcx':0,
    'rdx':0,
    'rbx':0,
    
    'rsp':0,
    'rbp':0,
    'rsi':0,
    'rdi':0,
    
    'r8' :0,
    'r9' :0,
    'r10':0,
    'r11':0,
    
    'r12':0,
    'r13':0,
    'r14':0,
}

# 读取可执行文件
def read_exe_file(path):
    infile = open(path)
    file = infile.readlines()[2:]
    return file

# 名称转换
def get_reg(s):
    s = s.upper()
    reg_name = {
    '0':'rax',
    '1':'rcx',
    '2':'rdx',
    '3':'rbx',
    
    '4':'rsp',
    '5':'rbp',
    '6':'rsi',
    '7':'rdi',
    
    '8':'r8' ,
    '9':'r9' ,
    'A':'r10',
    'B':'r11',
    
    'C':'r12',
    'D':'r13',
    'E':'r14',
    'F':None
    }
    return reg_name[s]

# 小端数据处理
def data_reverse(data):
    return int(''.join([data[i:i+2] for i in range(16,-2,-2)]),16)

# 标志处理
def flags(result):
    global zf,sf,of
    if result == 0:
        zf = 1
    else:
        zf = 0
    if result < 0:
        sf = 1
    else:
        sf = 0
    if result > 4294967296 or result < -4294967296: #溢出
        of = 1
    else:
        of = 0

# 标志位
zf = 0
sf = 0
of = 0

pc = 0
stat = 0

mem = [0 for i in range(101)]
reg['rsp'] = 100
try:
    exe_file = read_exe_file("./Y86_instr.coe")
    if len(exe_file) < 1:
        exit()
except FileNotFoundError:
    print(f"FileNotFoundError: {"./Y86_instr.coe"} not found, the progarm will use internal exe_file stored in this python code")
    #exe_file:
    #0   irmovq $1,%rax      30f001000000
    #1   irmovq $1,%r8       30f801000000
    #2   irmovq $0,%rbx      30f300000000
    #3   irmovq $100,%rdx    30f264000000
    #loop:
    #4   subq %rax,%rdx      6102
    #5   jl then             720a000000
    #6   irmovq $100,%rdx    30f264000000
    #7   addq %rax,%rbx      6003
    #8   addq %r8,%rax       6080
    #9   jmp loop            7004000000
    #then:
    #10  rmmovq %rbx,0(%rsp) 403400000000
    exe_file = ['30f001000000',
                '30f801000000',
                '30f300000000',
                '30f264000000',
                '6102',
                '720a000000',
                '30f264000000',
                '6003',
                '6080',
                '7004000000',
                '403400000000',
                ]

# 主循环
def cycle():
    global pc
    s = exe_file[pc]
    ins = s[0]
    fn = s[1]
    if ins == '0': # halt
        print("instr \'halt\' is not allowed to be used by application")
        return False
    elif ins == '1': # nop
        pc += 1
    elif ins == '2': # mov
        ra = get_reg(s[2])
        rb = get_reg(s[3])
        if fn == '0':   # rrmovq
            reg[rb] = reg[ra]           
        elif fn == '1': # cmovle
            if (sf ^ of) | zf:
                reg[rb] = reg[ra]         
        elif fn == '2': # cmovl
            if sf ^ of:
                reg[rb] = reg[ra]
        elif fn == '3': # cmove
            if zf:
                reg[rb] = reg[ra]
        elif fn == '4': #cmovne
            if ~zf:
                reg[rb] = reg[ra]
        elif fn == '5': #cmovge
            if ~(sf ^ of):
                reg[rb] = reg[ra]
        elif fn == '6': #cmovg
            if ~(sf ^ of) & ~ zf:
                reg[rb] = reg[ra]        
        pc += 1
    elif ins == '3': # irmovq
        ra = None
        rb = get_reg(s[3])
        data = data_reverse(s[4:])
        reg[rb] = data
        pc += 1
    elif ins == '4': # rmmovq
        ra = get_reg(s[2])
        rb = get_reg(s[3])
        data = reg[ra]
        mem[reg[rb]] = data
        pc += 1
    elif ins == '5': # mrmovq
        ra = get_reg(s[2])
        rb = get_reg(s[3])
        data = mem[reg[rb]]
        reg[ra] = data
        pc += 1
    elif ins == '6': # OPq
        ra = get_reg(s[2])
        rb = get_reg(s[3])
        if fn == '0':
            reg[rb] = reg[rb] + reg[ra] 
        elif fn == '1':
            reg[rb] = reg[rb] - reg[ra]
        elif fn == '2':
            reg[rb] = reg[rb] & reg[ra]
        elif fn == '3':
            reg[rb] = reg[rb] ^ reg[ra]
        flags(reg[rb])        
        pc += 1
    elif ins == '7': #jXX
        dst = data_reverse(s[2:])
        if fn =='0': # jmp
            pc = dst
        elif fn =='1': #jle
            if (sf ^ of) | zf:
                pc = dst
            else:
                pc += 1
        elif fn =='2': #jl
            if sf ^ of:
                pc = dst
            else:
                pc += 1
        elif fn =='3': #je
            if zf:
                pc = dst
            else:
                pc += 1
        elif fn =='4': #jne
            if ~zf:
                pc = dst
            else:
                pc += 1
        elif fn =='5': #jge
            if ~(sf ^ of):
                pc = dst
            else:
                pc += 1
        elif fn =='6': #jg
            if ~(sf ^ of) & ~ zf:
                pc = dst
            else:
                pc += 1
    elif ins == '8': #call
        dst = data_reverse(s[2:])
        reg['rsp'] -= 1
        mem[reg['rsp']] = pc + 1
        pc = dst
    elif ins == '9': # ret
        pc = mem[reg['rsp']]
        reg['rsp'] += 1
    elif ins == 'A': # pushq
        ra = get_reg(s[3])
        rb = get_reg(s[4])
        reg['rsp'] -= 1
        mem[reg['rsp']] = reg[ra]
        pc += 1
    elif ins == 'B': # popq
        ra = get_reg(s[3])
        rb = get_reg(s[4])
        reg[ra] = mem[reg['rsp']]
        reg['rsp'] += 1
        pc += 1
    return True

# 打印寄存器文件

def print_reg():
    print('-'*20+"reg file"+'-'*20)
    i = 0
    for reg_name in reg.keys():
        print("%s:%d"%(reg_name,reg[reg_name]),end='\t')
        i += 1
        if i % 4 == 0 or reg_name == 'r14':
            print()
    print('-'*20+"end"+'-'*20)
def print_mem():
    print('-'*20+"mem"+'-'*20)
    print('address:value')
    j = 0
    for i in range(len(mem)):
        print("%d:%d"%(i,mem[i]),end=' ')
        j += 1
        if j % 16 == 0:
            print()
    print('\n'+'-'*20+"end"+'-'*20)

# start
flag = True
while flag and pc < len(exe_file):
    flag = cycle()
print_mem()
print_reg()
