1#!/usr/bin/env python2.7
2
3# Copyright (c) 2013-2014 ARM Limited
4# All rights reserved
5#
6# The license below extends only to copyright in the software and shall
7# not be construed as granting a license to any other intellectual
8# property including but not limited to intellectual property relating
9# to a hardware implementation of the functionality of the software
10# licensed hereunder.  You may use the software subject to the license
11# terms below provided that you ensure that this notice is replicated
12# unmodified and in its entirety in all distributions of the software,
13# modified or unmodified, in source code or in binary form.
14#
15# Redistribution and use in source and binary forms, with or without
16# modification, are permitted provided that the following conditions are
17# met: redistributions of source code must retain the above copyright
18# notice, this list of conditions and the following disclaimer;
19# redistributions in binary form must reproduce the above copyright
20# notice, this list of conditions and the following disclaimer in the
21# documentation and/or other materials provided with the distribution;
22# neither the name of the copyright holders nor the names of its
23# contributors may be used to endorse or promote products derived from
24# this software without specific prior written permission.
25#
26# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37#
38# Authors: Ali Saidi
39#          Andreas Hansson
40
41# This script is used to dump protobuf instruction traces to ASCII
42# format. It assumes that protoc has been executed and already
43# generated the Python package for the inst messages. This can
44# be done manually using:
45# protoc --python_out=. inst.proto
46# The ASCII trace format uses one line per request.
47
48import protolib
49import sys
50
51# Import the packet proto definitions
52try:
53    import inst_pb2
54except:
55    print "Did not find protobuf inst definitions, attempting to generate"
56    from subprocess import call
57    error = call(['protoc', '--python_out=util', '--proto_path=src/proto',
58                  'src/proto/inst.proto'])
59    if not error:
60        print "Generated inst proto definitions"
61
62        try:
63            import google.protobuf
64        except:
65            print "Please install Python protobuf module"
66            exit(-1)
67
68        import inst_pb2
69    else:
70        print "Failed to import inst proto definitions"
71        exit(-1)
72
73def main():
74    if len(sys.argv) != 3:
75        print "Usage: ", sys.argv[0], " <protobuf input> <ASCII output>"
76        exit(-1)
77
78    # Open the file in read mode
79    proto_in = protolib.openFileRd(sys.argv[1])
80
81    try:
82        ascii_out = open(sys.argv[2], 'w')
83    except IOError:
84        print "Failed to open ", sys.argv[2], " for writing"
85        exit(-1)
86
87    # Read the magic number in 4-byte Little Endian
88    magic_number = proto_in.read(4)
89
90    if magic_number != "gem5":
91        print "Unrecognized file", sys.argv[1]
92        exit(-1)
93
94    print "Parsing instruction header"
95
96    # Add the packet header
97    header = inst_pb2.InstHeader()
98    protolib.decodeMessage(proto_in, header)
99
100    print "Object id:", header.obj_id
101    print "Tick frequency:", header.tick_freq
102    print "Memory addresses included:", header.has_mem
103
104    if header.ver != 0:
105        print "Warning: file version newer than decoder:", header.ver
106        print "This decoder may not understand how to decode this file"
107
108
109    print "Parsing instructions"
110
111    num_insts = 0
112    inst = inst_pb2.Inst()
113
114    # Decode the inst messages until we hit the end of the file
115    optional_fields = ('tick', 'type', 'inst_flags', 'addr', 'size', 'mem_flags')
116    while protolib.decodeMessage(proto_in,  inst):
117        # If we have a tick use it, otherwise count instructions
118        if inst.HasField('tick'):
119            tick = inst.tick
120        else:
121            tick = num_insts
122
123        if inst.HasField('nodeid'):
124            node_id = inst.nodeid
125        else:
126            node_id = 0;
127        if inst.HasField('cpuid'):
128            cpu_id = inst.cpuid
129        else:
130            cpu_id = 0;
131
132        ascii_out.write('%-20d: (%03d/%03d) %#010x @ %#016x ' % (tick, node_id, cpu_id,
133                                                  inst.inst, inst.pc))
134
135        if inst.HasField('type'):
136            ascii_out.write(' : %10s' % inst_pb2._INST_INSTTYPE.values_by_number[inst.type].name)
137
138        for mem_acc in inst.mem_access:
139            ascii_out.write(" %#x-%#x;" % (mem_acc.addr, mem_acc.addr + mem_acc.size))
140
141        ascii_out.write('\n')
142        num_insts += 1
143
144    print "Parsed instructions:", num_insts
145
146    # We're done
147    ascii_out.close()
148    proto_in.close()
149
150if __name__ == "__main__":
151    main()
152