forked from amibaid/Learning-Based-Cache-Eviction
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathemulator.py
218 lines (182 loc) · 6.75 KB
/
emulator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import sys
import cache
# load initial data into pseudo memory
MEM_SIZE = 32768
CODE_SIZE = 500
DEBUG = False
my_mem = [0 for i in range(MEM_SIZE)]
curr_index = 0
num_instrs = 0
comment = False
for line in sys.stdin.readlines():
line = line.split("//")[0].strip()
if line.isspace() or line == "":
continue
if line[0] == "@" and not comment:
# set current index
curr_index = int(line[1:], 16)
continue
if "/*" in line:
comment = True
if "*/" in line:
comment = False
continue
# otherwise plant the memory at the appropriate index and continue
if not comment:
my_mem[curr_index] = int(line, 16)
num_instrs += 1
curr_index += 1
# cache
mem_cache = cache.Cache();
# set pc to 0
pc = 0
# set regs to 0
regs = [0 for i in range(16)]
def is_valid(instr):
return any([f(instr) for f in [is_sub, is_mov, is_jump, is_ld, is_st, is_div, is_mul]])
def get_bit(num, i):
return ((num >> i) & 1)
# 0001aaaa0000tttt div rt, ra regs[t] = regs[a] / 2
def is_div(instr):
return all([get_bit(instr, i) == 0 for i in range(13, 16)]) and (get_bit(instr, 12) == 1) and all([get_bit(instr, i) == 0 for i in range(4, 8)])
# 0001aaaa0001tttt mul rt, ra regs[t] = regs[a] * 2
def is_mul(instr):
return all([get_bit(instr, i) == 0 for i in range(13, 16)]) and (get_bit(instr, 12) == 1) and all([get_bit(instr, i) == 0 for i in range(5, 8)]) and get_bit(instr, 4) == 1
# 0000aaaabbbbtttt sub rt,ra,rb regs[t] = regs[a] - regs[b]
def is_sub(instr):
return all([get_bit(instr, i) == 0 for i in range(12, 16)])
# 1000iiiiiiiitttt movl rt,i regs[t] = sign_extend(i)
# 1001iiiiiiiitttt movh rt,i regs[t] = (regs[t] & 0xff) | (i << 8)
def is_mov(instr):
return get_bit(instr, 15) == 1 and get_bit(instr, 14) == 0 and get_bit(instr, 13) == 0
# 1110aaaa0000tttt jz rt,ra pc = (regs[ra] == 0) ? regs[rt] : pc + 2
# 1110aaaa0001tttt jnz rt,ra pc = (regs[ra] != 0) ? regs[rt] : pc + 2
# 1110aaaa0010tttt js rt,ra pc = (regs[ra] < 0) ? regs[rt] : pc + 2
# 1110aaaa0011tttt jns rt,ra pc = (regs[ra] >= 0) ? regs[rt] : pc + 2
def is_jump(instr):
return (tuple(get_bit(instr, i) for i in range(12, 16)) == (0, 1, 1, 1)) and get_bit(instr, 6) == 0 and get_bit(instr, 7) == 0
# 1111aaaa0000tttt ld rt,ra regs[t] = mem[regs[a]]
def is_ld(instr):
return all([get_bit(instr, i) == 1 for i in range(12, 16)]) and all([get_bit(instr, i) == 0 for i in range(4, 8)])
# 1111aaaa0001tttt st rt,ra mem[regs[a]] = regs[t]
def is_st(instr):
return all([get_bit(instr, i) == 1 for i in range(12, 16)]) and all([get_bit(instr, i) == 0 for i in range(5, 8)]) and get_bit(instr, 4) == 1
# ra is bits [8,11]
def get_ra(instr):
return (instr >> 8) & 0b1111
# rb is bits [8,11]
def get_rb(instr):
return (instr >> 4) & 0b1111
# rt is bits [8,11]
def get_rt(instr):
return instr & 0b1111
# imm is bits [4,11]
def get_imm(instr):
return (instr >> 4) & 0b11111111
def get_reg(reg):
if reg == 0:
return 0
return regs[reg]
def set_reg(reg, val):
if reg == 0:
print(chr(val & 0b11111111), end='')
else:
regs[reg] = (val & 0xFFFF) # get last 16 bits
def do_sub(instr):
if DEBUG:
print("sub", get_rt(instr), get_ra(instr), get_rb(instr))
va = get_reg(get_ra(instr))
vb = get_reg(get_rb(instr))
result = va - vb
set_reg(get_rt(instr), result)
def do_mov(instr):
if get_bit(instr, 12) == 0:
# movl, we sign extend imm and replace full value
if DEBUG:
print("movl", get_rt(instr), get_imm(instr))
result = (sum([(1 << i) * get_bit(instr, 11) for i in range(8)]) << 8) + get_imm(instr)
else:
if DEBUG:
print("movh", get_rt(instr), get_imm(instr))
# movh, we use high 8 bits from imm and low 8 bits from rt
rt_old = get_reg(get_rt(instr)) & 0xFF
result = (get_imm(instr) << 8) + rt_old
set_reg(get_rt(instr), result)
def do_mul(instr):
if DEBUG:
print("mul", get_rt(instr), get_ra(instr))
result = (get_reg(get_ra(instr)) << 1)
set_reg(get_rt(instr), result)
def do_div(instr):
if DEBUG:
print("div", get_rt(instr), get_ra(instr))
result = (get_reg(get_ra(instr)) >> 1)
set_reg(get_rt(instr), result)
def do_jump(instr):
if DEBUG:
jump_bits = (get_bit(instr, 5), get_bit(instr, 4))
print("j%s" % ("z" if jump_bits == (0, 0) else "nz" if jump_bits == (0, 1) else "s" if jump_bits == (1, 0) else "ns"), get_rt(instr), get_ra(instr))
global pc
va = get_reg(get_ra(instr))
va_signbit = get_bit(va, 15)
vt = get_reg(get_rt(instr))
jump_bits = (get_bit(instr, 5), get_bit(instr, 4))
jump_condition = (jump_bits == (0, 0) and va == 0) or (jump_bits == (0, 1) and va != 0) or (jump_bits == (1, 0) and va_signbit == 1) or (jump_bits == (1, 1) and va_signbit == 0)
if jump_condition:
pc = vt - 2
def do_ld(instr):
if DEBUG:
print("ld", get_rt(instr), get_ra(instr))
print("st", get_rt(instr), get_ra(instr), my_mem[get_reg(get_ra(instr))//2], "from addr", get_reg(get_ra(instr)))
if (get_reg(get_ra(instr)) // 2) <= CODE_SIZE:
print("WARNING: LOADING FROM CODE SPACE")
va = get_reg(get_ra(instr))
#cache
mem_addr = va // 2
mem_cache.cache_lookup(mem_addr, my_mem)
set_reg(get_rt(instr), my_mem[va // 2])
def do_st(instr):
if DEBUG:
print("st", get_rt(instr), get_ra(instr), get_reg(get_rt(instr)), "into addr", get_reg(get_ra(instr)))
if (get_reg(get_ra(instr)) // 2) <= CODE_SIZE:
print("WARNING: WRITING TO CODE SPACE")
vt = get_reg(get_rt(instr))
va = get_reg(get_ra(instr))
my_mem[va // 2] = vt
#cache
mem_addr = va // 2
mem_cache.update_cache(mem_addr, my_mem)
def do_instruction(instr):
if is_sub(instr):
do_sub(instr)
elif is_mov(instr):
do_mov(instr)
elif is_div(instr):
do_div(instr)
elif is_mul(instr):
do_mul(instr)
elif is_jump(instr):
do_jump(instr)
elif is_ld(instr):
do_ld(instr)
elif is_st(instr):
do_st(instr)
else:
raise ValueError("weird instruction")
# interpret instructions and update regs, pc, pseudo-memory
num_cycles = 0
while num_cycles < 5000000:
# print(pc)
next_instr = my_mem[pc // 2]
# print("%d: %.4X" % (pc//2 + 1, next_instr))
if not is_valid(next_instr):
# print(hex(next_instr), "invalid at", pc)
break
do_instruction(next_instr)
pc += 2
num_cycles += 1
#output: cycles, FIFO hit rate, RRPV hit rate
print("Number of cycles: " + str(num_cycles))
cache_hits = mem_cache.cache_accuracy()
print("FIFO cache hit ratio:" + str(cache_hits[0]))
print("RRPV cache hit ratio:" + str(cache_hits[1]))