-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathmem.py
409 lines (368 loc) · 12.4 KB
/
mem.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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# -----------------------------------------------------------------------------
"""
Memory Functions
"""
# -----------------------------------------------------------------------------
import math
import util
import iobuf
import time
import random
# -----------------------------------------------------------------------------
_help_mem_2file = (
('<filename> <address/name> [len]', 'read from memory, write to file'),
(' filename', 'name of file'),
(' address', 'address of memory (hex)'),
(' name', 'name of memory region - see "map" command'),
(' len', 'length of memory region (hex)'),
)
_help_mem_verify = (
('<filename> <address/name> [len]', 'read from file, verify against memory'),
(' filename', 'name of file'),
(' address', 'address of memory (hex)'),
(' name', 'name of memory region - see "map" command'),
(' len', 'length of memory region (hex) - defaults to filesize'),
)
_help_mem_region = (
('<address/name> <len>', 'memory region'),
(' address', 'address of memory (hex)'),
(' name', 'name of memory region - see "map" command'),
(' len', 'length of memory region (hex) - defaults to region size or 0x40'),
)
_help_mem_rd = (
('<adr>', 'address (hex)'),
)
_help_mem_wr = (
('<adr> <val>', 'address (hex)'),
('', 'value (hex)'),
)
# -----------------------------------------------------------------------------
class region(object):
"""class to represent a memory region"""
# note: The meta data is used to store device specific region information
# e.g. a flash sector/bank number used in a flash erase routine
def __init__(self, name, adr, size, meta = None):
self.name = name
self.adr = adr
self.size = size
self.end = self.adr + self.size - 1
self.meta = meta
def overlap(self, x):
"""return True if this region and x overlap"""
return max(self.adr, x.adr) <= min(self.end, x.end)
def col_str(self):
"""return a 4 string column for this region [name, range, size, meta]"""
meta_str = (str(self.meta), '')[self.meta is None]
return [self.name, ': %08x %08x' % (self.adr, self.end), util.memsize(self.size), meta_str]
# -----------------------------------------------------------------------------
def flash_regions(device, region_map):
"""divide the named memory into sized memory regions"""
regions = []
for x in region_map:
if len(x) == 2:
# no meta information: set it all to None
(name, region_sizes) = x
meta = (None,) * len(region_sizes)
elif len(x) == 3:
# provided meta information - make sure it's per region
(name, region_sizes, meta) = x
assert len(region_sizes) == len(meta), 'need meta information for each flash region'
else:
assert False, 'bad flash region specification'
# the regions are based on the peripheral memory space
base_adr = device.peripherals[name].address
total_size = device.peripherals[name].size
adr = base_adr
for (s, m) in zip(region_sizes, meta):
regions.append(region(name, adr, s, m))
adr += s
# make sure the regions cover the entire memory space of the peripheral
assert base_adr + total_size == adr, "regions don't encompass all memory"
return regions
# -----------------------------------------------------------------------------
class mem(object):
def __init__(self, cpu):
self.cpu = cpu
self.menu = (
('d8', self.cmd_display8, _help_mem_region),
('d16', self.cmd_display16, _help_mem_region),
('d32', self.cmd_display32, _help_mem_region),
('>file', self.cmd_mem2file, _help_mem_2file),
('md5', self.cmd_md5, _help_mem_region),
('pic', self.cmd_pic, _help_mem_region),
('rd8', self.cmd_rd8, _help_mem_rd),
('rd16', self.cmd_rd16, _help_mem_rd),
('rd32', self.cmd_rd32, _help_mem_rd),
('t8', self.cmd_test8, _help_mem_region),
('t16', self.cmd_test16, _help_mem_region),
('t32', self.cmd_test32, _help_mem_region),
('verify', self.cmd_verify, _help_mem_verify),
('wr8', self.cmd_wr8, _help_mem_wr),
('wr16', self.cmd_wr16, _help_mem_wr),
('wr32', self.cmd_wr32, _help_mem_wr),
)
def cmd_rd(self, ui, args, n):
"""memory read command for n bits"""
if util.wrong_argc(ui, args, (1,)):
return
adr = util.sex_arg(ui, args[0], self.cpu.width)
if adr == None:
return
adr = util.align(adr, n)
ui.put('[0x%08x] = ' % adr)
ui.put('0x%%0%dx\n' % (n >> 2) % self.cpu.rd(adr, n))
def cmd_rd8(self, ui, args):
"""read 8 bits"""
self.cmd_rd(ui, args, 8)
def cmd_rd16(self, ui, args):
"""read 16 bits"""
self.cmd_rd(ui, args, 16)
def cmd_rd32(self, ui, args):
"""read 32 bits"""
self.cmd_rd(ui, args, 32)
def cmd_wr(self, ui, args, n):
"""memory write command for n bits"""
if util.wrong_argc(ui, args, (1,2)):
return
adr = util.sex_arg(ui, args[0], self.cpu.width)
if adr == None:
return
adr = util.align(adr, n)
val = 0
if len(args) == 2:
val = util.int_arg(ui, args[1], util.limit_32, 16)
if val == None:
return
val = util.mask_val(val, n)
self.cpu.wr(adr, val, n)
ui.put('[0x%08x] = ' % adr)
ui.put('0x%%0%dx\n' % (n >> 2) % val)
def cmd_wr8(self, ui, args):
"""write 8 bits"""
self.cmd_wr(ui, args, 8)
def cmd_wr16(self, ui, args):
"""write 16 bits"""
self.cmd_wr(ui, args, 16)
def cmd_wr32(self, ui, args):
"""write 32 bits"""
self.cmd_wr(ui, args, 32)
def cmd_mem2file(self, ui, args):
"""read from memory, write to file"""
x = util.file_mem_args(ui, args, self.cpu.device)
if x is None:
return
(name, adr, size) = x
if size is None:
ui.put('invalid length')
return
# adjust the address and length
adr = util.align(adr, 32)
n = util.nbytes_to_nwords(size, 32)
# read memory, write to file object
mf = iobuf.write_file(ui, 'writing to %s' % name, name, n * 4)
self.cpu.rdmem32(adr, n, mf)
mf.close()
def cmd_verify(self, ui, args):
"""verify memory against file"""
x = util.file_mem_args(ui, args, self.cpu.device)
if x is None:
return
(name, adr, size) = x
# check the file
filesize = util.file_arg(ui, name)
if filesize is None:
return
# round up the filesize - the io object will return 0xff for any bytes beyond EOF
filesize = util.roundup(filesize, 32)
if size is None:
# no length on the command line - verify the filesize
size = filesize
if size > filesize:
# region is larger than file - just verify the filesize
size = filesize
# adjust the address and length
adr = util.align(adr, 32)
n = util.nbytes_to_nwords(size, 32)
# read memory, verify against file object
mf = iobuf.verify_file(ui, 'verify %s (%d bytes):' % (name, n * 4), name, n * 4)
self.cpu.rdmem32(adr, n, mf)
mf.close()
def __display(self, ui, args, width):
"""display memory: as width bits"""
x = util.mem_args(ui, args, self.cpu.device)
if x is None:
return
(adr, n) = x
if n == 0:
return
if n is None:
n = 0x40
# round down address to 16 byte boundary
adr &= ~15
# round up n to an integral multiple of 16 bytes
n = (n + 15) & ~15
# print the header
if width == 8:
ui.put('address 0 1 2 3 4 5 6 7 8 9 A B C D E F\n')
elif width == 16:
ui.put('address 0 2 4 6 8 A C E\n')
elif width == 32:
ui.put('address 0 4 8 C\n')
else:
assert False, 'bad width'
# read and print the data
for i in range(n >> 4):
# read 4, 32-bit words (16 bytes per line)
io = iobuf.data_buffer(32)
self.cpu.rdmem(adr, 4, io)
# work out the data string
io.convert(width, 'le')
data_str = str(io)
# work out the ascii string
io.convert(8, 'le')
ascii_str = io.ascii_str()
ui.put('%08x: %s %s\n' % (adr, data_str, ascii_str))
adr += 16
def cmd_display8(self, ui, args):
"""display memory 8 bits"""
self.__display(ui, args, 8)
def cmd_display16(self, ui, args):
"""display memory 16 bits"""
self.__display(ui, args, 16)
def cmd_display32(self, ui, args):
"""display memory 32 bits"""
self.__display(ui, args, 32)
def __analyze(self, buf, ofs, n):
"""return a character to respresent the buffer"""
b0 = buf[ofs]
if b0 is None:
c = ' '
elif b0 == 0:
c = '-'
elif b0 == 0xff:
c = '.'
else:
c = '$'
for i in range(1, n):
k = buf[ofs + i]
if k is not None and k != b0:
return '$'
return c
def cmd_pic(self, ui, args):
"""display a pictorial summary of memory"""
x = util.mem_args(ui, args, self.cpu.device)
if x is None:
return
(adr, n) = x
if n == 0:
return
if n is None:
n = 0x40
# round down address to 32-bit byte boundary
adr &= ~3
# round up n to an integral multiple of 4 bytes
n = (n + 3) & ~3
# work out how many rows, columns and bytes per symbol we should display
cols_max = 70
cols = cols_max + 1
bps = 1
# we try to display a matrix that is roughly square
while cols > cols_max:
bps *= 2
cols = int(math.sqrt(float(n)/float(bps)))
rows = int(math.ceil(n / (float(cols) * float(bps))))
# bytes per row
bpr = cols * bps
# work out the none padding
nwords = n >> 2
nwords_displayed = (((cols * rows * bps) + 3) & ~3) >> 2
none_pad = [None,] * ((nwords_displayed - nwords) * 4)
# read the memory
if n > (16 << 10):
ui.put('reading memory ...\n')
data = iobuf.data_buffer(32)
self.cpu.rdmem32(adr, nwords, data)
data.convert8(mode = 'le')
# add the none padding
data.buf.extend(none_pad)
# display the summary
ui.put("'.' all ones, '-' all zeroes, '$' various\n")
ui.put('%d (0x%x) bytes per symbol\n' % (bps, bps))
ui.put('%d (0x%x) bytes per row\n' % (bpr, bpr))
ui.put('%d cols x %d rows\n' % (cols, rows))
# display the matrix
ofs = 0
for y in range(rows):
s = []
adr_str = '0x%08x: ' % (adr + ofs)
for x in range(cols):
s.append(self.__analyze(data.buf, ofs, bps))
ofs += bps
ui.put('%s%s\n' % (adr_str, ''.join(s)))
def cmd_md5(self, ui, args):
"""calculate an md5 hash of memory"""
x = util.mem_args(ui, args, self.cpu.device)
if x is None:
return
(adr, n) = x
if n == 0:
return
if n is None:
n = 0x40
# round down address to 32-bit byte boundary
adr &= ~3
# round up n to an integral multiple of 4 bytes
n = (n + 3) & ~3
# read the memory
if n > (16 << 10):
ui.put('reading memory ...\n')
data = iobuf.data_buffer(32)
t_start = time.time()
self.cpu.rdmem(adr, n >> 2, data)
t_end = time.time()
ui.put('%s\n' % data.md5('le'))
ui.put('%.2f KiB/sec\n' % (float(n)/((t_end - t_start) * 1024.0)))
def cmd_test(self, width, ui, args):
"""test memory with a write and readback"""
x = util.mem_args(ui, args, self.cpu.device)
if x is None:
return
(adr, n) = x
if n == 0:
return
if n is None:
n = 0x40
# round down address to 32-bit byte boundary
adr &= ~3
# round up n to an integral multiple of 4 bytes
n = (n + 3) & ~3
# convert to n 32/16/8-bit units
nx = int(n / (width >> 3))
maxval = (1 << width) - 1
# we will typically be testing ram, so halt the cpu.
self.cpu.halt()
# build a random write buffer
wrbuf = iobuf.data_buffer(width)
[wrbuf.write(random.randint(0, maxval)) for i in range(nx)]
# write it to memory
t_start = time.time()
self.cpu.wrmem(adr, nx, wrbuf)
t_end = time.time()
ui.put('write %.2f KiB/sec\n' % (float(n)/((t_end - t_start) * 1024.0)))
# read it from memory
rdbuf = iobuf.data_buffer(width)
t_start = time.time()
self.cpu.rdmem(adr, nx, rdbuf)
t_end = time.time()
ui.put('read %.2f KiB/sec\n' % (float(n)/((t_end - t_start) * 1024.0)))
ui.put('read %s write\n' % ('!=', '==')[wrbuf.compare(rdbuf)])
def cmd_test8(self, ui, args):
"""test memory with 8-bit write and readback"""
self.cmd_test(8, ui, args)
def cmd_test16(self, ui, args):
"""test memory with 16-bit write and readback"""
self.cmd_test(16, ui, args)
def cmd_test32(self, ui, args):
"""test memory with 32-bit write and readback"""
self.cmd_test(32, ui, args)
# -----------------------------------------------------------------------------