forked from Patt-Senior-Design/core-design
-
Notifications
You must be signed in to change notification settings - Fork 0
/
checkmem.py
executable file
·165 lines (156 loc) · 6.37 KB
/
checkmem.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
#!/usr/bin/env python3
import sys
RAMBASE = 0x20000000//4
RAMSIZE = 0x8000000//4
# two categories of entry:
# 1. read (lw/lh/lb/lhu/lbu/lbcmp)
# 2. write (sw/sh/sb)
class MemoryEntry:
def __init__(self, line: int, time: int, category: str, addr: int, wdata: int = None):
self.line = line
self.time = time
self.category = category
self.addr = addr
self.rdata = None
self.wdata = wdata
def getLoadResult(entry: MemoryEntry, memValue: int) -> int:
memValue >>= (entry.addr & 3) * 8
if entry.category == "lh":
memValue = ((memValue & 0x7fff) - (memValue & 0x8000)) & 0xffffffff
elif entry.category == "lb":
memValue = ((memValue & 0x7f) - (memValue & 0x80)) & 0xffffffff
elif entry.category == "lhu":
memValue = memValue & 0xffff
elif entry.category == "lbu":
memValue = memValue & 0xff
return memValue
def getStoreResult(entry: MemoryEntry, memValue: int) -> int:
shift = (entry.addr & 3) * 8
regValue = entry.wdata << shift
if entry.category == "sw":
return regValue
if entry.category == "sh":
mask = 0xffff << shift
return (memValue & ~mask) | (regValue & mask)
if entry.category == "sb":
mask = 0xff << shift
return (memValue & ~mask) | (regValue & mask)
return None
def getCmpResult(entry: MemoryEntry, ram: list) -> int:
base = (entry.addr // 4) & ~1
byte = entry.wdata & 0xff
result = 0
for i in range(8):
word = ram[base-RAMBASE]
for j in range(4):
result = (result >> 1) | (0x80000000 if ((word & 0xff) == byte) else 0)
word >>= 8
base += 1
return result
class MemoryTrace:
def __init__(self, logfile: str):
self.logfile = logfile
def parse(self) -> bool:
self.entries = []
lsqids = [None] * 16
linenum = 1
success = True
with open(self.logfile, "r") as f:
for line in f:
fields = line.split()
time = int(fields[0])
category = fields[1]
if category[0] == "l":
# lw/lh/lb/lhu/lbu/lbcmp (read request)
addr = int(fields[2], 16)
if category == "lbcmp":
op2 = int(fields[3], 16)
lsqid = int(fields[4])
else:
op2 = None
lsqid = int(fields[3])
lsqids[lsqid] = len(self.entries)
self.entries.append(MemoryEntry(linenum, time, category, addr, op2))
if (category[1] == "h" and (addr & 1)) or (category[1] == "w" and (addr & 3)) or (category == "lbcmp" and (addr & 7)):
print("WARN: misaligned {} at line {} ({}ns)".format(category, linenum, time))
elif category[0] == "s":
# sw/sh/sb (write)
addr = int(fields[2], 16)
wdata = int(fields[3], 16)
self.entries.append(MemoryEntry(linenum, time, category, addr, wdata))
if (category[1] == "h" and (addr & 1)) or (category[1] == "w" and (addr & 3)):
print("WARN: misaligned {} at line {} ({}ns)".format(category, linenum, time))
elif category == "resp":
# read response
lsqid = int(fields[2])
if lsqids[lsqid] is None:
print("FAIL checkmem at line {} ({}ns): orphaned response".format(linenum, time))
success = False
else:
if fields[3] == "error":
self.entries[lsqids[lsqid]].rdata = "<error>"
else:
rdata = int(fields[3], 16)
self.entries[lsqids[lsqid]].rdata = rdata
lsqids[lsqid] = None
elif category == "flush":
for index in lsqids:
if index is not None:
self.entries[index].rdata = "<flushed>"
lsqids = [None] * 16
linenum += 1
for index in lsqids:
if index:
entry = self.entries[index]
print("FAIL checkmem at line {} ({}ns): orphaned request".format(entry.line, entry.time))
success = False
return success
def check(self) -> tuple:
memory = [0] * RAMSIZE
for entry in self.entries:
if entry.rdata == "<error>":
continue
if entry.category[0] == "l":
if entry.rdata == "<flushed>":
continue
memAddr = (entry.addr // 4) - RAMBASE
if memAddr < 0 or memAddr >= len(memory):
#print("WARN: not checking line {}, addr {:08x} not in RAM".format(entry.line, entry.addr))
continue
memValue = memory[memAddr]
if entry.category == "lbcmp":
result = getCmpResult(entry, memory)
else:
result = getLoadResult(entry, memValue)
if entry.rdata != result:
return (entry,result)
elif entry.category[0] == "s":
memAddr = (entry.addr // 4) - RAMBASE
if memAddr < 0 or memAddr >= len(memory):
#print("WARN: not checking line {}, addr {:08x} not in RAM".format(entry.line, entry.addr))
continue
memValue = memory[memAddr]
memory[memAddr] = getStoreResult(entry, memValue)
return None
def main() -> int:
if len(sys.argv) < 2:
print("Usage: checklog.py <logfile>")
exit(1)
memtrace = MemoryTrace(sys.argv[1])
if not memtrace.parse():
return 1
mismatch = memtrace.check()
if mismatch:
entry = mismatch[0]
if entry.rdata is not None:
gotVal = "{:08x}".format(entry.rdata)
else:
gotVal = "<no response>"
expectedVal = mismatch[1]
print("FAIL checkmem at line {} ({}ns): {} {:08x} (got {}, expected {:08x})".format(
entry.line, entry.time, entry.category, entry.addr, gotVal, expectedVal))
return 1
print("PASS checkmem")
return 0
if __name__ == "__main__":
exit(main())