-
Notifications
You must be signed in to change notification settings - Fork 0
/
compare_traces.py
133 lines (119 loc) · 5.07 KB
/
compare_traces.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
#!/usr/bin/python
# Filename: compare_traces.py
# Created by: Jacob R. Stevens
# Email: [email protected]
# Date Created: 06/27/2016
# Description: Compare the traces generated by the ISS and cpu_tracker.sv
import subprocess
import argparse
import sys
import glob
import os
def create_sim_trace():
cmd = ['sim', '-t']
with open('sim_trace.log', 'w') as log:
ret = subprocess.call(cmd, stdout=log)
if ret:
sys.exit("ERROR: 'sim -t' command failed.")
def create_cpu_trace():
cmd = ['make', 'system.sim']
with open(os.devnull, 'w') as null_file:
ret = subprocess.call(cmd, stdout=null_file, stderr=null_file)
if ret:
sys.exit('Error: make failed. Make sure your processor compiles first')
def clean_cpu_trace():
cleaned_output = ''
with open('cpu_trace.log', 'r') as trace_file:
for line in trace_file:
broken_line_arr = line.split()
if len(broken_line_arr) >= 5:
# Modify beginning of instruction entry
# that is, the line with PC, core, instruction, and mnemonics
# turn instruction into uppercase hex
broken_line_arr[3] = broken_line_arr[3].upper()
# if the instruction is a jump, change the destination addr to hex
if broken_line_arr[4] == 'J' or broken_line_arr[4] == 'JAL':
broken_line_arr[5] = broken_line_arr[5].upper()
# turn PC into uppercase hex and remove space between PC and (Core n)
first_entry = broken_line_arr[0].upper() + broken_line_arr[1]
broken_line_arr = [first_entry] + broken_line_arr[2:]
new_line = ' '.join(broken_line_arr) + '\n'
elif len(broken_line_arr) == 0:
new_line = '\n'
elif broken_line_arr[0] == 'PC' or broken_line_arr[0][0] == 'R':
# Modify the line that updates the PC or a register
broken_line_arr[2] = broken_line_arr[2].upper()
new_line = ' ' + ' '.join(broken_line_arr) + '\n'
elif broken_line_arr[0] == '[word':
# Modify the line that specifies where a word is read from
broken_line_arr[3] = broken_line_arr[3].upper()
new_line = ' ' + ' '.join(broken_line_arr) + '\n'
elif broken_line_arr[0][0] == '[':
# Modify the line that updates a memory location
broken_line_arr[0] = broken_line_arr[0].upper()
broken_line_arr[2] = broken_line_arr[2].upper()
new_line = ' ' + ' '.join(broken_line_arr) + '\n'
cleaned_output += new_line
with open('cleaned_cpu_trace.log', 'w') as trace_file:
trace_file.write(cleaned_output[:-1])
def clean_sim_trace():
cleaned_output = ''
with open('sim_trace.log', 'r') as trace_file:
line = trace_file.readline()
# Skip past the header portion to the actual execution trace
while line and line[8:13] != '(Core':
line = trace_file.readline()
# Clean up the instructions up through HALT
while line and line[-5:-1] != 'HALT':
broken_line_arr = line.split()
if 0 < len(broken_line_arr) < 5:
# Make the lines that specify updates have two indents
# because I like it better that way.
new_line = ' ' + ' '.join(broken_line_arr) + '\n'
else:
new_line = ' '.join(broken_line_arr) + '\n'
cleaned_output += new_line
line = trace_file.readline()
# DO the Halt
if line and line[-5:-1] == 'HALT':
broken_line_arr = line.split()
new_line = ' '.join(broken_line_arr) + '\n'
cleaned_output += new_line
line = trace_file.readline()
broken_line_arr = line.split()
new_line = ' ' + ' '.join(broken_line_arr) + '\n'
cleaned_output += new_line
with open('cleaned_sim_trace.log', 'w') as trace_file:
trace_file.write(cleaned_output)
if __name__ == '__main__':
description = 'Compare your processor\'s trace to that of the simulator.'
description += 'This script expects to be ran at the top level of your repo.'
description += 'If a test name is provided, it should be the full name of the'
description += 'test case, but not include the file extension or path'
help = 'Run this specific test. Optional. If not specified, the current '
help += 'meminit.hex is used.'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('test_name', metavar= 'test_name', type=str, nargs='?',
help=help)
args = parser.parse_args()
if args.test_name:
asm_dir = './asmFiles/' + args.test_name + '.asm'
try:
asm_file = glob.glob(asm_dir)[0]
except:
sys.exit("ERROR: Please provide the exact name of a test case.")
ret = subprocess.call(['asm', asm_file])
if ret:
sys.exit('ERROR: ' + asm_file + ' could not be assembled.')
elif not os.path.isfile('./meminit.hex'):
sys.exit('ERROR: Could not find an existing meminit.hex.')
create_sim_trace()
clean_sim_trace()
create_cpu_trace()
clean_cpu_trace()
cmd = ['diff', 'cleaned_cpu_trace.log', 'cleaned_sim_trace.log']
with open(os.devnull, 'w') as null_file:
ret = subprocess.call(cmd, stdout=null_file, stderr=null_file)
if ret:
cmd = ['diff', '-y', 'cleaned_cpu_trace.log', 'cleaned_sim_trace.log']
subprocess.call(cmd)