diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-01-29 20:08:56 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-02-01 13:03:21 +0100 |
commit | 2415649297d32409d9a30c51a53958ac736388e6 (patch) | |
tree | 1527fa6d5ab847fad2c343ee7e34977a268834ad /tools | |
parent | 2d15176b78bea3dee508bfae2342e8d04b090f13 (diff) |
split up state.xml into multiple parts
- state.xml : main file
- state_2d.xml.h : 2d state
- state_3d.xml.h : 3d state
- state_hi.xml.h : host interface state (registers)
- common.xml : shared bits between state.xml, cmdstream.xml and isa.xml
also beginnings of automatic state management, currently for RS only
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/dump_separate_cmdbuf.py | 190 | ||||
-rw-r--r-- | tools/etnaviv/parse_rng.py | 73 |
2 files changed, 240 insertions, 23 deletions
diff --git a/tools/dump_separate_cmdbuf.py b/tools/dump_separate_cmdbuf.py new file mode 100755 index 0000000..677cf20 --- /dev/null +++ b/tools/dump_separate_cmdbuf.py @@ -0,0 +1,190 @@ +#!/usr/bin/python +''' +Parse separate command buffer (outside of fdr), used for processing debug output. +''' +# Copyright (c) 2012-2013 Wladimir J. van der Laan +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sub license, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +from __future__ import print_function, division, unicode_literals +import argparse +import os, sys, struct +import json +from collections import defaultdict + +from binascii import b2a_hex + +# Parse rules-ng-ng format for state space +from etnaviv.parse_rng import parse_rng_file, format_path, BitSet, Domain + +DEBUG = False + +# Number of words to ignore at start of command buffer +# A PIPE3D command will be inserted here by the kernel if necessary +CMDBUF_IGNORE_INITIAL = 8 + +def int_as_float(i): + '''Return float with binary representation of unsigned int i''' + return struct.unpack(b'f', struct.pack(b'I', i))[0] + +def fixp_as_float(i): + '''Return float from 16.16 fixed-point value of i''' + return i / 65536.0 + +COMPS = 'xyzw' +def format_state(pos, value, fixp, state_map): + try: + path = state_map.lookup_address(pos) + path_str = format_path(path) #+ ('(0x%05X)' % pos) + except KeyError: + path = None + path_str = '0x%05X' % pos + desc = ' ' + path_str + if fixp: + desc += ' = %f' % fixp_as_float(value) + else: + # For uniforms, show float value + if (pos >= 0x05000 and pos < 0x06000) or (pos >= 0x07000 and pos < 0x08000): + num = pos & 0xFFF + spec = 'u%i.%s' % (num//16, COMPS[(num//4)%4]) + desc += ' := %f (%s)' % (int_as_float(value), spec) + elif path is not None: + register = path[-1][0] + desc += ' := ' + desc += register.describe(value) + return desc + +def dump_command_buffer(f, buf, depth, state_map): + ''' + Dump Vivante command buffer contents in human-readable + format. + ''' + indent = ' ' * len(depth) + f.write('{\n') + state_base = 0 + state_count = 0 + state_format = 0 + next_cmd = 0 #CMDBUF_IGNORE_INITIAL + payload_start_ptr = 0 + payload_end_ptr = 0 + op = 0 + size = len(buf) + ptr = 0 + states = [] # list of (ptr, state_addr) tuples + while ptr < size: + hide = False + value = buf[ptr] + if ptr >= next_cmd: + #f.write('\n') + op = value >> 27 + payload_start_ptr = payload_end_ptr = ptr + 1 + if op == 1: + state_base = (value & 0xFFFF)<<2 + state_count = (value >> 16) & 0x3FF + if state_count == 0: + state_count = 0x400 + state_format = (value >> 26) & 1 + payload_end_ptr = payload_start_ptr + state_count + desc = "LOAD_STATE (1) Base: 0x%05X Size: %i Fixp: %i" % (state_base, state_count, state_format) + if options.hide_load_state: + hide = True + elif op == 2: + desc = "END (2)" + elif op == 3: + desc = "NOP (3)" + elif op == 4: + desc = "DRAW_2D (4)" + elif op == 5: + desc = "DRAW_PRIMITIVES (5)" + payload_end_ptr = payload_start_ptr + 3 + elif op == 6: + desc = "DRAW_INDEXED_PRIMITIVES (6)" + payload_end_ptr = payload_start_ptr + 4 + elif op == 7: + desc = "WAIT (7)" + elif op == 8: + desc = "LINK (8)" + payload_end_ptr = payload_start_ptr + 1 + elif op == 9: + desc = "STALL (9)" + payload_end_ptr = payload_start_ptr + 1 + elif op == 10: + desc = "CALL (10)" + payload_end_ptr = payload_start_ptr + 1 + elif op == 11: + desc = "RETURN (11)" + elif op == 13: + desc = "CHIP_SELECT (13)" + else: + desc = "UNKNOWN (%i)" % op + next_cmd = (payload_end_ptr + 1) & (~1) + elif ptr < payload_end_ptr: # Parse payload + if op == 1: + pos = (ptr - payload_start_ptr)*4 + state_base + states.append((ptr, pos, state_format, value)) + desc = format_state(pos, value, state_format, state_map) + else: + desc = "" + else: + desc = "PAD" + if not hide: + f.write(indent + ' 0x%08x' % value) + if ptr != (size-1): + f.write(", /* %s */\n" % desc) + else: + f.write(" /* %s */\n" % desc) + ptr += 1 + f.write(indent + '}') + +def parse_arguments(): + parser = argparse.ArgumentParser(description='Parse execution data log stream.') + parser.add_argument('input_file', metavar='INFILE', type=str, + help='FDR file') + parser.add_argument('rules_file', metavar='RULESFILE', type=str, + help='State map definition file (rules-ng-ng)') + parser.add_argument('-l', '--hide-load-state', dest='hide_load_state', + default=False, action='store_const', const=True, + help='Hide "LOAD_STATE" entries, this can make command stream a bit easier to read') + return parser.parse_args() + +shader_num = 0 + +def main(): + args = parse_arguments() + state_xml = parse_rng_file(args.rules_file) + state_map = state_xml.lookup_domain('VIVS') + global options + options = args + import re + + with open(args.input_file,'r') as f: + # parse ascii + values = [] + for line in f: + value = line.strip() + if value.startswith(':'): + value = int(value[1:9], 16) + values.append(value) + + dump_command_buffer(sys.stdout, values, [], state_map) + sys.stdout.write('\n') + +if __name__ == '__main__': + main() + diff --git a/tools/etnaviv/parse_rng.py b/tools/etnaviv/parse_rng.py index 89d0834..90eafdd 100644 --- a/tools/etnaviv/parse_rng.py +++ b/tools/etnaviv/parse_rng.py @@ -28,6 +28,7 @@ import os, sys, struct from collections import OrderedDict from lxml import etree as ET # parsing from itertools import izip +from os import path ns = "{http://nouveau.freedesktop.org/}" XML_BOOL = {'1':True, '0':False, 'false':False, 'true':True, 'yes':True, 'no':False} @@ -557,6 +558,7 @@ class Tag: USE_GROUP = ns+'use-group' BRIEF = ns+'brief' DOC = ns+'doc' + IMPORT = ns+'import' REG_TO_SIZE = {REG8:8, REG16:16, REG32:32, REG64:64} @@ -587,7 +589,7 @@ def intdh(s): else: return int(s) -def visit_xml(syms, type_resolve_list, parent, root): +def visit_xml(syms, type_resolve_list, parent, root, imports): ''' Visit an xml element, build an in-memory object for it, and add it to the in-memory parent object. @@ -596,9 +598,12 @@ def visit_xml(syms, type_resolve_list, parent, root): if root.tag == Tag.BRIEF: parent.brief += root.text return None - if root.tag in Tag.DOC: + if root.tag == Tag.DOC: parent.doc += root.text return None + if root.tag == Tag.IMPORT: + imports.append(root.attrib['file']) + return None # Pre-process attributes attr = {} @@ -613,31 +618,37 @@ def visit_xml(syms, type_resolve_list, parent, root): attr['size'] = Tag.REG_TO_SIZE[root.tag] # Instantiate object from tag - obj = visit[root.tag](parent, **attr) - - # Add this object to parent object - if parent is not None and obj is not None: - if not parent.add_child(obj): - raise ValueError('Cannot add child %s to %s' % - (obj.__class__.__name__, parent.__class__.__name__)) - - # If a type, add object to symbol table - if isinstance(obj, Type): - if not obj.name in syms: - syms[obj.name] = obj - else: - raise ValueError('Duplicate type name %s' % obj.name) + if root.tag == Tag.DOMAIN and attr['name'] in syms: + # allow re-opening a domain that was created before, to add more + # state + obj = syms[attr['name']] + assert(isinstance(obj, Domain)) + else: + obj = visit[root.tag](parent, **attr) + + # Add this object to parent object + if parent is not None and obj is not None: + if not parent.add_child(obj): + raise ValueError('Cannot add child %s to %s' % + (obj.__class__.__name__, parent.__class__.__name__)) + + # If a type, add object to symbol table + if isinstance(obj, Type): + if not obj.name in syms: + syms[obj.name] = obj + else: + raise ValueError('Duplicate type name %s' % obj.name) - # If it has a type attribute, add it to the type resolve list - if isinstance(obj, TypedValue): - type_resolve_list.append(obj) + # If it has a type attribute, add it to the type resolve list + if isinstance(obj, TypedValue): + type_resolve_list.append(obj) # Visit children for child in root.iterchildren(tag=ET.Element): - visit_xml(syms, type_resolve_list, obj, child) + visit_xml(syms, type_resolve_list, obj, child, imports) return obj -def parse_rng(f): +def parse_rng(f, import_path=''): ''' Parse a rules-ng-ng XML tree from a file object. @@ -658,10 +669,25 @@ def parse_rng(f): # and patch them into the right place in the second pass type_table = OrderedDict() type_resolve_list = [] + imports = [] - retval = visit_xml(type_table, type_resolve_list, None, root) + retval = visit_xml(type_table, type_resolve_list, None, root, imports) if not isinstance(retval, Database): raise ValueError('Top-level element must be database') + + # Load imports + already_imported = set() + while imports: + filename = imports.pop() + if filename in already_imported: + continue + with open(path.join(import_path,filename), 'r') as f: + tree = ET.parse(f) + root = tree.getroot() + # import, merging duplicate domains + visit_xml(type_table, type_resolve_list, None, root, imports) + + # add types list to toplevel database retval.types = type_table # Resolve types pass @@ -694,8 +720,9 @@ def parse_rng(f): return retval def parse_rng_file(filename): + import_path = path.dirname(filename) with open(filename, 'r') as f: - return parse_rng(f) + return parse_rng(f, import_path) def format_path(path): '''Format path into state space as string''' |