1 |
4 |
ja_rd |
#!/usr/bin/env python
|
2 |
|
|
"""
|
3 |
|
|
svg_op_table.py: Build 3 SVG files with the MCS51 opcode table decorated with
|
4 |
|
|
cycle count information extracted from the cycle count simulation log file.
|
5 |
|
|
"""
|
6 |
|
|
__author__ = "Jose A. Ruiz"
|
7 |
|
|
__license__ = "LGPL"
|
8 |
|
|
|
9 |
|
|
|
10 |
|
|
import sys
|
11 |
|
|
import getopt
|
12 |
|
|
|
13 |
|
|
|
14 |
|
|
def read_cycle_info(filename):
|
15 |
|
|
"""
|
16 |
|
|
the file should have 256 lines of text.
|
17 |
|
|
Each line has 4 comma-separated fields:
|
18 |
|
|
opcode, minimum cycle count, maximum cycle count, number of executions.
|
19 |
|
|
The number of executions is the number of times the opcode was executed by
|
20 |
|
|
the simulation that produced the log.
|
21 |
|
|
If this number is zero, or if the minimum cycle count is >= 999, then
|
22 |
|
|
the opcode has not been executed and there's no cycle count data for it.
|
23 |
|
|
|
24 |
|
|
This function returns a list of 256 tuples sorted by opcode, with the
|
25 |
|
|
above 3 values (the opcode is excluded).
|
26 |
|
|
"""
|
27 |
|
|
|
28 |
|
|
# Open file and read it into a list of lines.
|
29 |
|
|
fin = open(filename, "r")
|
30 |
|
|
lines = fin.readlines()
|
31 |
|
|
fin.close()
|
32 |
|
|
|
33 |
|
|
info = [[]] * 256;
|
34 |
|
|
|
35 |
|
|
for line in lines:
|
36 |
|
|
fields = line.split(',')
|
37 |
|
|
opc = int(fields[0],16)
|
38 |
|
|
info[opc] = (int(fields[1]), int(fields[2]), int(fields[3]))
|
39 |
|
|
return info
|
40 |
|
|
|
41 |
|
|
|
42 |
|
|
def read_opcode_info(filename):
|
43 |
|
|
"""
|
44 |
|
|
Read a table of MCS51 opcodes from a plain text file.
|
45 |
|
|
Rather than writing here a lengthy explanation I invite you to see the
|
46 |
|
|
opcode table text file "opcode_info.txt".
|
47 |
|
|
Since the file is known, we don't provide for formatting errors, missing
|
48 |
|
|
lines or any kind of trouble.
|
49 |
|
|
This file has been copy-pasted straight from Keil's website and slightly
|
50 |
|
|
edited.
|
51 |
|
|
"""
|
52 |
|
|
|
53 |
|
|
# Open file and read it into a list of lines.
|
54 |
|
|
fin = open(filename, "r")
|
55 |
|
|
lines = fin.readlines()
|
56 |
|
|
fin.close()
|
57 |
|
|
|
58 |
|
|
# We'll build a table with 256 entries, one per opcode.
|
59 |
|
|
info = [[]] * 256;
|
60 |
|
|
|
61 |
|
|
for line in lines:
|
62 |
|
|
[opcode, _, line] = line.partition('\t')
|
63 |
|
|
[nbytes, _, line] = line.partition('\t')
|
64 |
|
|
[mnemonic, _, operands] = line.partition('\t')
|
65 |
|
|
i = int(opcode, 16)
|
66 |
|
|
info[i] = [mnemonic.strip(), operands.strip(), int(nbytes)]
|
67 |
|
|
|
68 |
|
|
return info
|
69 |
|
|
|
70 |
|
|
def opcode_unimplemented(opc):
|
71 |
|
|
"""Return true if the opcode is not implemented (implemented as NOP)."""
|
72 |
|
|
# FIXME this should be optional, like the implementation itself.
|
73 |
|
|
return opc=="DA" or opc=="XCHD"
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
def build_svg_table(info, cycles, part):
|
77 |
|
|
"""
|
78 |
|
|
Render the opcode table, or one half of it, in SVG format.
|
79 |
|
|
@arg info Array of opcode information as returned by read_opcode_info.
|
80 |
|
|
@arg cycles Array of opcode cycle counts as returned by read_cycle_info.
|
81 |
|
|
@arg part Can be one of ("left","right","full").
|
82 |
|
|
Return a string in SVG format to be written to a file.
|
83 |
|
|
"""
|
84 |
|
|
|
85 |
|
|
|
86 |
|
|
# (lc,hc) is the range of columns we're going to draw. It can be the whole
|
87 |
|
|
# table or the left or right half.
|
88 |
|
|
if part=="left":
|
89 |
|
|
lc = 0
|
90 |
|
|
hc = 8
|
91 |
|
|
elif part=="right":
|
92 |
|
|
lc = 8
|
93 |
|
|
hc = 16
|
94 |
|
|
else:
|
95 |
|
|
lc = 0
|
96 |
|
|
hc = 16
|
97 |
|
|
|
98 |
|
|
# Hardcode the rendering parameters: size of the cells, etc.
|
99 |
|
|
# Note that other parameters (font size and text coordinates) are hardcoded
|
100 |
|
|
# in the string literals below.
|
101 |
|
|
scale = 1.0
|
102 |
|
|
c_width = 300
|
103 |
|
|
c_height = 200
|
104 |
|
|
cr_height = c_height
|
105 |
|
|
cr_width = c_width / 2
|
106 |
|
|
cc_height = c_height / 2
|
107 |
|
|
cc_width = c_width
|
108 |
|
|
|
109 |
|
|
# Compute the SVG frame size according to the selected part.
|
110 |
|
|
w = hc - lc
|
111 |
|
|
width = c_width*w + cr_width + 20
|
112 |
|
|
height = c_height*16 + cc_height + 20
|
113 |
|
|
|
114 |
|
|
# This is the SVG header template.
|
115 |
|
|
header = \
|
116 |
|
|
"<svg xmlns='http://www.w3.org/2000/svg' \n" + \
|
117 |
|
|
"xmlns:xlink='http://www.w3.org/1999/xlink' \n" + \
|
118 |
|
|
"width='%d' height='%d' viewbox='0 0 %d %d' \n" + \
|
119 |
|
|
"preserveAspectRatio='none'>\n\n"
|
120 |
|
|
|
121 |
|
|
# We'll append all the SVG text onto this variable.
|
122 |
|
|
svg = ""
|
123 |
|
|
|
124 |
|
|
# Build the SVG header with the selected size.
|
125 |
|
|
svg = svg + header % (width, height, width, height)
|
126 |
|
|
|
127 |
|
|
# SVG definitions template. There's 3 cells, for the table borders and
|
128 |
|
|
# the table body.
|
129 |
|
|
defs = \
|
130 |
|
|
'<defs>\n' + \
|
131 |
|
|
'<!-- Basic table cell -->\n' + \
|
132 |
|
|
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="s"/>\n' + \
|
133 |
|
|
'<!-- Row index cell -->\n' + \
|
134 |
|
|
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="r"/>\n' + \
|
135 |
|
|
'<!-- Col index cell -->\n' + \
|
136 |
|
|
'<rect height="%d" width="%d" stroke="black" stroke-width="1" id="c"/>\n' + \
|
137 |
|
|
'</defs>\n\n'
|
138 |
|
|
|
139 |
|
|
# Build SVG definitions block with its parameters -- cell sizes.
|
140 |
|
|
svg = svg + defs % (c_height, c_width, cr_height, cr_width, cc_height, cc_width)
|
141 |
|
|
|
142 |
|
|
# This is a SVG group template for the main table cell.
|
143 |
|
|
# Note that the font sizes and text coordinates are hardcoded!
|
144 |
|
|
base_cell = \
|
145 |
|
|
'<g transform="translate(%d,%d) scale(%f)">\n' + \
|
146 |
|
|
'<use x="0" y="0" xlink:href="#s" fill="%s"/>\n' + \
|
147 |
|
|
'<text x="80" y="90" font-family="sans-serif" font-size="55">%s</text>\n' + \
|
148 |
|
|
'<text x="80" y="140" font-family="sans-serif" font-size="40">%s</text>\n' + \
|
149 |
|
|
'<text x="10" y="40" font-family="verdana" fill="red" font-size="40">%s</text>\n' + \
|
150 |
|
|
'<text x="260" y="40" font-family="verdana" fill="blue" font-size="40">%d</text>\n' + \
|
151 |
|
|
'</g>\n\n'
|
152 |
|
|
|
153 |
|
|
# SCG group template for a cell to the left of the table with a row number.
|
154 |
|
|
row_index_cell = \
|
155 |
|
|
'<g transform="translate(%d,%d) scale(%f)">\n' + \
|
156 |
|
|
'<use x="0" y="0" xlink:href="#r" fill="white"/>\n' + \
|
157 |
|
|
'<text x="80" y="90" font-family="sans-serif" font-size="55">%01X</text>\n' + \
|
158 |
|
|
'</g>\n\n'
|
159 |
|
|
|
160 |
|
|
# SCG group template for a cell at the top of the table with a col number.
|
161 |
|
|
col_index_cell = \
|
162 |
|
|
'<g transform="translate(%d,%d) scale(%f)">\n' + \
|
163 |
|
|
'<use x="0" y="0" xlink:href="#c" fill="white"/>\n' + \
|
164 |
|
|
'<text x="80" y="70" font-family="sans-serif" font-size="55">%01X</text>\n' + \
|
165 |
|
|
'</g>\n\n'
|
166 |
|
|
|
167 |
|
|
# Build the top row of the table: cells with the column number.
|
168 |
|
|
for col in range(lc,hc):
|
169 |
|
|
y = 10
|
170 |
|
|
x = 10 + (cr_width + (col-lc)*c_width)*scale
|
171 |
|
|
svg = svg + col_index_cell % (x, 10, scale, col)
|
172 |
|
|
|
173 |
|
|
# Now, for each of the 16 rows...
|
174 |
|
|
for row in range(16):
|
175 |
|
|
# ...compute the row vertical coordinate...
|
176 |
|
|
y = 10 + (cc_height + row*c_height)*scale
|
177 |
|
|
# ...render the leftmost cell with the row index...
|
178 |
|
|
svg = svg + row_index_cell % (10, y, scale, row)
|
179 |
|
|
# ...and render the row of main-table-body cells.
|
180 |
|
|
|
181 |
|
|
# for each of the cells in the column range we're rendering...
|
182 |
|
|
for col in range(lc,hc):
|
183 |
|
|
# ...compute the horizintal coordinate of the cell...
|
184 |
|
|
x = 10 + (cr_width + (col-lc)*c_width)*scale
|
185 |
|
|
|
186 |
|
|
# ...and extract the cycle count data from the array.
|
187 |
|
|
opc = col*16 + row
|
188 |
|
|
min = cycles[opc][0]
|
189 |
|
|
max = cycles[opc][1]
|
190 |
|
|
# When min/=max we need to display both values (conditional
|
191 |
|
|
# jumps, for instance).
|
192 |
|
|
# Those opcodes with a min value >=999 have not been executed by
|
193 |
|
|
# the simulation and we'll render them in a darker shade of grey.
|
194 |
|
|
if min < 999:
|
195 |
|
|
if min==max:
|
196 |
|
|
count = str(min)
|
197 |
|
|
else:
|
198 |
|
|
count = str(min) + "/" + str(max)
|
199 |
|
|
color = "white"
|
200 |
|
|
else:
|
201 |
|
|
count = " "
|
202 |
|
|
color = "#e0e0e0"
|
203 |
|
|
|
204 |
|
|
# Render the cell with all its parameters.
|
205 |
|
|
|
206 |
|
|
|
207 |
|
|
# Render the 'optional' opcodes in red.
|
208 |
|
|
if opcode_unimplemented(info[opc][0]):
|
209 |
|
|
color = "#f0b0b0"
|
210 |
|
|
|
211 |
|
|
cell = base_cell % (x, y, scale, color, info[opc][0], info[opc][1], count, info[opc][2])
|
212 |
|
|
|
213 |
|
|
svg = svg + cell
|
214 |
|
|
|
215 |
|
|
# Done, close the SVG element and we're done.
|
216 |
|
|
svg = svg + '</svg>'
|
217 |
|
|
|
218 |
|
|
return svg
|
219 |
|
|
|
220 |
|
|
|
221 |
|
|
def write_cycle_table(cycle_info, c_table_file):
|
222 |
|
|
"""
|
223 |
|
|
Writes the cycle count info in the format of a C literal table.
|
224 |
|
|
Meant to be copied and pasted into the B51 simulator.
|
225 |
|
|
"""
|
226 |
|
|
|
227 |
|
|
txt = "typedef struct {\n"
|
228 |
|
|
txt = txt + " int min;\n"
|
229 |
|
|
txt = txt + " int max;\n"
|
230 |
|
|
txt = txt + "} cycle_count_t;\n"
|
231 |
|
|
txt = txt + "\n\n"
|
232 |
|
|
txt = txt + "cycle_count_t cycle_count[256] = {\n "
|
233 |
|
|
for i in range(len(cycle_info)):
|
234 |
|
|
item = cycle_info[i]
|
235 |
|
|
if item[2] == 0:
|
236 |
|
|
txt = txt + "{ 0, 0}, "
|
237 |
|
|
else:
|
238 |
|
|
txt = txt + "{%2u,%2u}, " % (item[0], item[1])
|
239 |
|
|
if (i % 8) == 7:
|
240 |
|
|
txt = txt + "\n "
|
241 |
|
|
txt = txt + "};\n\n"
|
242 |
|
|
|
243 |
|
|
|
244 |
|
|
fout = open(c_table_file, "w")
|
245 |
|
|
fout.write(txt)
|
246 |
|
|
fout.close()
|
247 |
|
|
|
248 |
|
|
|
249 |
|
|
def main(argv):
|
250 |
|
|
"""Main body of the program."""
|
251 |
|
|
|
252 |
|
|
# We should parse the command line arguments, etc.
|
253 |
|
|
# For this quick-and-dirty script we'll hardcode all the parameters...
|
254 |
|
|
|
255 |
|
|
# ...the target svg file names...
|
256 |
|
|
svg_base_filename = "./table"
|
257 |
|
|
# ...the target text file name where a C-format table with the cycle counts
|
258 |
|
|
# will be written to...
|
259 |
|
|
c_table_file = "./cycle_table.c"
|
260 |
|
|
# ...and the source CSV cycle count log file. Note this path is the default
|
261 |
|
|
# working path for the Modelsim simulations, change if necessary.
|
262 |
|
|
cycle_log_filename = "../../sim/cycle_count_log.csv"
|
263 |
|
|
|
264 |
|
|
# Read cycle count data...
|
265 |
|
|
cycle_info = read_cycle_info(cycle_log_filename)
|
266 |
|
|
# ...and read opcode table data (instruction mnemonics and byte counts).
|
267 |
|
|
opcode_info = read_opcode_info("opcode_info.txt")
|
268 |
|
|
|
269 |
|
|
# First of all, write the C-format cycle table, to be copied and pasted
|
270 |
|
|
# into the B51 simulator.
|
271 |
|
|
write_cycle_table(cycle_info, c_table_file)
|
272 |
|
|
|
273 |
|
|
# We can render the opcode table 'whole', resulting in a wide table, or
|
274 |
|
|
# we can render the left and right halves separately, which gives a format
|
275 |
|
|
# better suted for a printed page.
|
276 |
|
|
|
277 |
|
|
# So, for all three possible rendering formats...
|
278 |
|
|
parts = ("left", "right", "full")
|
279 |
|
|
# ...render the opcode table.
|
280 |
|
|
for part in parts:
|
281 |
|
|
|
282 |
|
|
# Build the SVG text for the table...
|
283 |
|
|
svg = build_svg_table(opcode_info, cycle_info, part)
|
284 |
|
|
# ...and write it to the target file.
|
285 |
|
|
fout = None
|
286 |
|
|
try:
|
287 |
|
|
full_filename = svg_base_filename + "_" + part + ".svg"
|
288 |
|
|
fout = open(full_filename, "w")
|
289 |
|
|
fout.write(svg)
|
290 |
|
|
fout.close()
|
291 |
|
|
print "SVG opcode table written to %s" % full_filename
|
292 |
|
|
except:
|
293 |
|
|
print "Trouble opening %s for output" % full_filename
|
294 |
|
|
finally:
|
295 |
|
|
if fout: fout.close()
|
296 |
|
|
|
297 |
|
|
|
298 |
|
|
if __name__ == "__main__":
|
299 |
|
|
main(sys.argv[1:])
|
300 |
|
|
sys.exit(0)
|
301 |
|
|
|
302 |
|
|
|