/* * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * * 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, sublicense, * 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 shall be included * in all copies or substantial portions of the Software. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * author: Jerome Glisse */ #include #include #include #include #include "list.h" #include "rdb.h" union blocku { unsigned reg[2]; unsigned pkt[256]; }; #define TYPE_REG 0 #define TYPE_PKT 1 struct block { struct list_head list; unsigned type; union blocku u; }; struct ctx { struct list_head blocks; struct rdb *rdb; }; void ctx_add_reg(struct ctx *ctx, unsigned reg, unsigned v) { struct block *b; switch (reg) { /* dont unduplicate some of the sync reg */ case 0x00008040: // WAIT_UNTIL case 0x000085f0: // CP_COHER_CNTL case 0x000085f4: // CP_COHER_SIZE case 0x000085f8: // CP_COHER_BASE break; default: LIST_FOR_EACH_ENTRY(b, &ctx->blocks, list) { if (b->type == TYPE_REG && b->u.reg[0] == reg) { b->u.reg[1] = v; list_del(&b->list); list_add_tail(&b->list, &ctx->blocks); return; } } break; } b = malloc(sizeof(*b)); b->u.reg[0] = reg; b->u.reg[1] = v; b->type = TYPE_REG; list_add_tail(&b->list, &ctx->blocks); } struct block *ctx_add_pkt(struct ctx *ctx, unsigned count) { struct block *b; b = malloc(sizeof(*b)); b->type = TYPE_PKT; b->u.pkt[0] = count + 1; list_add_tail(&b->list, &ctx->blocks); return b; } void ctx_init(struct ctx *ctx, struct rdb *rdb) { list_init_head(&ctx->blocks); ctx->rdb = rdb; } void ctx_print(struct ctx *ctx) { struct block *b, *tmp; LIST_FOR_EACH_ENTRY_SAFE(b, tmp, &ctx->blocks, list) { switch (b->type) { case TYPE_REG: { const struct rdb_reg *reg; reg = rdb_find_reg_any_domain(ctx->rdb, b->u.reg[0]); if (reg) { printf("0x%08x 0x%08x %s\n", b->u.reg[0], b->u.reg[1], reg->name); } else { printf("0x%08x 0x%08x ??\n", b->u.reg[0], b->u.reg[1]); } break; } case TYPE_PKT: { unsigned it; it = ((b->u.pkt[1] >> 8) & 0xff); switch (it) { case 0x29: case 0x2b: case 0x2d: case 0x2e: case 0x35: printf("0x%08x PKT3 0x%02x DRAW *******************************************\n", b->u.pkt[1], it); break; default: printf("0x%08x PKT3 0x%02x\n", b->u.pkt[1], it); break; } for (unsigned i = 2; i <= b->u.pkt[0]; i++) { printf("0x%08x\n", b->u.pkt[i]); } break; } default: break; } list_del_init(&b->list); free(b); } } char *line_skip(char *line, unsigned nspace) { do { if (*line == ' ') { nspace--; } line++; } while (nspace); return line; } void annotate(struct ctx *ctx, FILE *file) { char line[128], *tmp; unsigned offset, value, ndw = 0, pkt = 0, it, doprint = 0, pktidx = 0; struct block *b; while (!feof(file)) { if (fgets(line, sizeof(line), file) == NULL) { continue; } line[strlen(line) - 1] = 0; tmp = strstr(line, "] ["); if (tmp == NULL) { printf("%s\n", line); continue; } tmp = strchr(tmp + 4, ']'); if (tmp == NULL) { printf("%s\n", line); continue; } value = strtoul(tmp + 2, &tmp, 0); if (tmp == NULL) { printf("%s\n", line); continue; } if (ndw) { switch (pkt) { case 3: switch (it) { case 0x68: if (!offset) { offset = (value << 2) + 0x8000; } else { ctx_add_reg(ctx, offset, value); offset += 4; } break; case 0x69: if (!offset) { offset = (value << 2) + 0x28000; } else { ctx_add_reg(ctx, offset, value); offset += 4; } break; default: b->u.pkt[pktidx++] = value; break; } break; case 0: default: ctx_add_reg(ctx, offset, value); offset += 4; break; } ndw--; } else { if (doprint) { doprint = 0; ctx_print(ctx); } pkt = (value >> 30) & 3; switch (pkt) { case 0: offset = (value & 0xffff) << 2; ndw = ((value >> 16) & 0x3fff) + 1; break; case 3: offset = 0; ndw = ((value >> 16) & 0x3fff) + 1; pktidx = 1; it = ((value >> 8) & 0xff); switch (it) { case 0x68: case 0x69: break; case 0x29: case 0x2b: case 0x2d: case 0x2e: case 0x35: doprint = 1; /* fallthrough */ default: b = ctx_add_pkt(ctx, ndw); b->u.pkt[pktidx++] = value; break; } break; case 1: case 2: default: break; } } } } int main(int argc, char *argv[]) { struct ctx ctx; struct rdb rdb; FILE *file; if (argc != 3) { printf("usage %s rdb ibfile\n", argv[0]); return -1; } file = fopen(argv[1], "r"); if (file == NULL) { fprintf(stderr, "failed reading %s\n", argv[1]); return -1; } rdb_init(&rdb); if (rdb_read(&rdb, file)) { fprintf(stderr, "failed reading %s\n", argv[1]); return -1; } fclose(file); file = fopen(argv[2], "r"); if (file == NULL) { fprintf(stderr, "failed reading %s\n", argv[2]); return -1; } ctx_init(&ctx, &rdb); annotate(&ctx, file); fclose(file); }