#!/usr/bin/env python
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
# Copyright IBM Corp. 2008
#
# Authors: Hollis Blanchard <hollisb@us.ibm.com>

import sys
import os
import struct

global recordsize
global lasttime
global sec
lasttime = 0
sec = 0
datafmt=">6I"
recordsize = struct.calcsize(datafmt)

def get_op(instr):
        return (instr >> 26);

def get_xop(instr):
        return (instr >> 1) & 0x3ff;

def get_sprn(instr):
	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0)

def get_dcrn(instr):
	return ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);

def get_rs(instr):
	return (instr >> 21) & 0x1f;

def get_ra(instr):
	return (instr >> 16) & 0x1f;

def get_rb(instr):
	return (instr >> 11) & 0x1f;

def get_tlbwe_type(instr):
	ws = (instr >> 11) & 0x1f;
	if ws == 0:
		return "PAGEID"
	elif ws == 1:
		return "XLAT"
	elif ws == 2:
		return "ATTRIB"
	else:
		return "UNKNOWN"

def get_name(instr):
	if get_op(instr)==3:
		return "trap"
	elif get_op(instr)==19:
		if get_xop(instr) == 50:
			return "rfi"
		else:
			return "unknown"
	elif get_op(instr)==31:
		if get_xop(instr) == 83:
			return "mfmsr"

		elif get_xop(instr) == 87:
			return "lbzx"

		elif get_xop(instr) == 131:
			return "wrtee"

		elif get_xop(instr) == 146:
			return "mtmsr"

		elif get_xop(instr) == 163:
			return "wrteei"

		elif get_xop(instr) == 215:
			return "stbx"

		elif get_xop(instr) == 247:
			return "stbux"

		elif get_xop(instr) == 279:
			return "lhzx"

		elif get_xop(instr) == 311:
			return "lhzux"

		elif get_xop(instr) == 323:
			return "mfdcr"

		elif get_xop(instr) == 339:
			return "mfspr"

		elif get_xop(instr) == 407:
			return "sthx"

		elif get_xop(instr) == 439:
			return "sthux"

		elif get_xop(instr) == 451:
			return "mtdcr"

		elif get_xop(instr) == 467:
			return "mtspr"

		elif get_xop(instr) == 470:
			return "dcbi"

		elif get_xop(instr) == 534:
			return "lwbrx"

		elif get_xop(instr) == 566:
			return "tlbsync"

		elif get_xop(instr) == 662:
			return "stwbrx"

		elif get_xop(instr) == 978:
			return "tlbwe"

		elif get_xop(instr) == 914:
			return "tlbsx"

		elif get_xop(instr) == 790:
			return "lhbrx"

		elif get_xop(instr) == 918:
			return "sthbrx"

		elif get_xop(instr) == 966:
			return "iccci"

		else:
			return "unknown"

	elif get_op(instr) == 32:
		return "lwz"

	elif get_op(instr) == 33:
		return "lwzu"

	elif get_op(instr) == 34:
		return "lbz"

	elif get_op(instr) == 35:
		return "lbzu"

	elif get_op(instr) == 36:
		return "stw"

	elif get_op(instr) == 37:
		return "stwu"

	elif get_op(instr) == 38:
		return "stb"

	elif get_op(instr) == 39:
		return "stbu"

	elif get_op(instr) == 40:
		return "lhz"

	elif get_op(instr) == 41:
		return "lhzu"

	elif get_op(instr) == 44:
		return "sth"

	elif get_op(instr) == 45:
		return "sthu"

	else:
		return "unknown"

def get_sprn_name(sprn):
		if sprn == 0x01a:
			return "SRR0"
		elif sprn == 0x01b:
			return "SRR1"
		elif sprn == 0x3b2:
			return "MMUCR"
		elif sprn == 0x030:
			return "PID"
		elif sprn == 0x03f:
			return "IVPR"
		elif sprn == 0x3b3:
			return "CCR0"
		elif sprn == 0x378:
			return "CCR1"
		elif sprn == 0x11f:
			return "PVR"
		elif sprn == 0x03d:
			return "DEAR"
		elif sprn == 0x03e:
			return "ESR"
		elif sprn == 0x134:
			return "DBCR0"
		elif sprn == 0x135:
			return "DBCR1"
		elif sprn == 0x11c:
			return "TBWL"
		elif sprn == 0x11d:
			return "TBWU"
		elif sprn == 0x016:
			return "DEC"
		elif sprn == 0x150:
			return "TSR"
		elif sprn == 0x154:
			return "TCR"
		elif sprn == 0x110:
			return "SPRG0"
		elif sprn == 0x111:
			return "SPRG1"
		elif sprn == 0x112:
			return "SPRG2"
		elif sprn == 0x113:
			return "SPRG3"
		elif sprn == 0x114:
			return "SPRG4"
		elif sprn == 0x115:
			return "SPRG5"
		elif sprn == 0x116:
			return "SPRG6"
		elif sprn == 0x117:
			return "SPRG7"
		elif sprn == 0x190:
			return "IVOR0"
		elif sprn == 0x191:
			return "IVOR1"
		elif sprn == 0x192:
			return "IVOR2"
		elif sprn == 0x193:
			return "IVOR3"
		elif sprn == 0x194:
			return "IVOR4"
		elif sprn == 0x195:
			return "IVOR5"
		elif sprn == 0x196:
			return "IVOR6"
		elif sprn == 0x197:
			return "IVOR7"
		elif sprn == 0x198:
			return "IVOR8"
		elif sprn == 0x199:
			return "IVOR9"
		elif sprn == 0x19a:
			return "IVOR10"
		elif sprn == 0x19b:
			return "IVOR11"
		elif sprn == 0x19c:
			return "IVOR12"
		elif sprn == 0x19d:
			return "IVOR13"
		elif sprn == 0x19e:
			return "IVOR14"
		elif sprn == 0x19f:
			return "IVOR15"
		else:
			return "UNKNOWN"

def get_special(instr):
	if get_op(instr) == 31:
		if (get_xop(instr) == 339) or (get_xop(instr) == 467):
			sprn = get_sprn(instr);
			return ("- sprn 0x%03x %8s\n" % (sprn, get_sprn_name(sprn)))
		elif (get_xop(instr) == 323 ) or (get_xop(instr) == 451):
			return ("- dcrn 0x%03x\n" % get_dcrn(instr))
		elif (get_xop(instr) == 978 ) or (get_xop(instr) == 451):
			return ("- ws -> %8s\n" % get_tlbwe_type(instr))
	return "\n"

def process_record(data):
	global lasttime
	global sec
	try:
		time, pc, instr, rsval, raval, rbval = struct.unpack(datafmt, data)
	except struct.error:
		sys.stdout.write("struct error parsing record\n")
		raise

	if lasttime > time:
		sec = sec + 1
	lasttime = time
	rsreg = ""
	if rsval != 0:
		rsreg = "@r%02d" % get_rs(instr)
	rareg = ""
	if raval != 0:
		rareg = "@r%02d" % get_ra(instr)
	rbreg = ""
	if rbval != 0:
		rbreg = "@r%02d" % get_rb(instr)
	pdata = (sec, time, instr, pc, rsval, rsreg, raval, rareg, rbval, rbreg, get_name(instr), get_special(instr))
	sys.stdout.write("%3d.%09d: %10x @ %10x %10x%4s %10x%4s %10x%4s %8s %s" % pdata)

def parse_file(path):
	global recordsize
	f = open(path, "rb")
	while 1:
		data = f.read(recordsize)
		if len(data) == 0:
			sys.stdout.write("reached EOF\n")
			break;
		try:
			process_record(data)
		except struct.error:
			sys.stdout.write("struct error parsing record\n")
			break
	f.close()

if __name__ == '__main__':
	logpath = sys.argv[1]
	labels = ("time", "instr", "pc", "rsval", "raval", "rbval", "mnemonic", "- context info")
	sys.stdout.write("%13s: %10s @ %10s %14s %14s %14s %8s %s\n" % labels)
	parse_file(logpath)
