/*
* This file is part of libbluray
* Copyright (C) 2009-2017 Petri Hintukainen <phintuka@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "mobj_print.h"
#include "mobj_data.h"
#include "hdmv_insn.h"
#include <stdio.h>
static const char * const psr_info[128] = {
"/* PSR0: Interactive graphics stream number */",
"/* PSR1: Primary audio stream number */",
"/* PSR2: PG TextST stream number and PiP PG stream number */",
"/* PSR3: Angle number */",
"/* PSR4: Title number */",
"/* PSR5: Chapter number */",
"/* PSR6: PlayList ID */",
"/* PSR7: PlayItem ID */",
"/* PSR8: Presentation time */",
"/* PSR9: Navigation timer */",
"/* PSR10: Selected button ID */",
"/* PSR11: Page ID */",
"/* PSR12: User style number */",
"/* RO: PSR13: User age */",
"/* PSR14: Secondary audio stream number and secondary video stream number */",
"/* RO: PSR15: player capability for audio */",
"/* RO: PSR16: Language code for audio */",
"/* RO: PSR17: Language code for PG and Text subtitles */",
"/* RO: PSR18: Menu description language code */",
"/* RO: PSR19: Country code */",
"/* RO: PSR20: Region code */ /* 1 - A, 2 - B, 4 - C */",
"/* RO: PSR21: Output Mode Preference */ /* 0 - 2D, 1 - 3D */",
"/* PSR22: Stereoscopic status */ /* 2D / 3D */ ",
"/* RO: PSR23: display capablity */",
"/* RO: PSR24: 3D capability */",
"/* RO: PSR25: UHD capability */",
"/* RO: PSR26: UHD display capability */",
"/* RO: PSR27: HDR preference */",
"/* RO: PSR28: SDR conversion preference */",
"/* RO: PSR29: player capability for video */",
"/* RO: PSR30: player capability for text subtitle */",
"/* RO: PSR31: Player profile and version */",
"/* PSR32 */",
"/* PSR33 */",
"/* PSR34 */",
"/* PSR35 */",
"/* PSR36: backup PSR4 */",
"/* PSR37: backup PSR5 */",
"/* PSR38: backup PSR6 */",
"/* PSR39: backup PSR7 */",
"/* PSR40: backup PSR8 */",
"/* PSR41: */",
"/* PSR42: backup PSR10 */",
"/* PSR43: backup PSR11 */",
"/* PSR44: backup PSR12 */",
"/* PSR45: */",
"/* PSR46: */",
"/* PSR47: */",
"/* RO: PSR48: Characteristic text caps */",
"/* RO: PSR49: Characteristic text caps */",
"/* RO: PSR50: Characteristic text caps */",
"/* RO: PSR51: Characteristic text caps */",
"/* RO: PSR52: Characteristic text caps */",
"/* RO: PSR53: Characteristic text caps */",
"/* RO: PSR54: Characteristic text caps */",
"/* RO: PSR55: Characteristic text caps */",
"/* RO: PSR56: Characteristic text caps */",
"/* RO: PSR57: Characteristic text caps */",
"/* RO: PSR58: Characteristic text caps */",
"/* RO: PSR59: Characteristic text caps */",
"/* RO: PSR60: Characteristic text caps */",
"/* RO: PSR61: Characteristic text caps */",
/* PSR62 */ NULL,
/* PSR63 */ NULL,
/* PSR64 */ NULL,
/* PSR65 */ NULL,
/* PSR66 */ NULL,
/* PSR67 */ NULL,
/* PSR68 */ NULL,
/* PSR69 */ NULL,
/* PSR70 */ NULL,
/* PSR71 */ NULL,
/* PSR72 */ NULL,
/* PSR73 */ NULL,
/* PSR74 */ NULL,
/* PSR75 */ NULL,
/* PSR76 */ NULL,
/* PSR77 */ NULL,
/* PSR78 */ NULL,
/* PSR79 */ NULL,
/* PSR80 */ NULL,
/* PSR81 */ NULL,
/* PSR82 */ NULL,
/* PSR83 */ NULL,
/* PSR84 */ NULL,
/* PSR85 */ NULL,
/* PSR86 */ NULL,
/* PSR87 */ NULL,
/* PSR88 */ NULL,
/* PSR89 */ NULL,
/* PSR90 */ NULL,
/* PSR91 */ NULL,
/* PSR92 */ NULL,
/* PSR93 */ NULL,
/* PSR94 */ NULL,
/* PSR95 */ NULL,
/* PSR96 */ NULL,
/* PSR97 */ NULL,
/* PSR98 */ NULL,
/* PSR99 */ NULL,
/* PSR100 */ NULL,
/* PSR101 */ NULL,
"/* PSR102: BD+ receive */",
"/* PSR103: BD+ send */",
"/* PSR104: BD+ shared */",
/* PSR105 */ NULL,
/* PSR106 */ NULL,
/* PSR107 */ NULL,
/* PSR108 */ NULL,
/* PSR109 */ NULL,
/* PSR110 */ NULL,
/* PSR111 */ NULL,
/* PSR112 */ NULL,
/* PSR113 */ NULL,
/* PSR114 */ NULL,
/* PSR115 */ NULL,
/* PSR116 */ NULL,
/* PSR117 */ NULL,
/* PSR118 */ NULL,
/* PSR119 */ NULL,
/* PSR120 */ NULL,
/* PSR121 */ NULL,
/* PSR122 */ NULL,
/* PSR123 */ NULL,
/* PSR124 */ NULL,
/* PSR125 */ NULL,
/* PSR126 */ NULL,
/* PSR127 */ NULL,
};
#if 0
static const char * const insn_groups[4] = {
"BRANCH",
"COMPARE",
"SET",
};
static const char * const insn_group_branch[8] = {
"GOTO",
"JUMP",
"PLAY",
};
static const char * const insn_group_set[8] = {
"SET",
"SETSYSTEM",
};
#endif
static const char * const insn_opt_set[32] = {
NULL,
"move",
"swap",
"add",
"sub",
"mul",
"div",
"mod",
"rnd",
"and",
"or",
"xor",
"bset",
"bclr",
"shl",
"shr",
};
static const char * const insn_opt_setsys[32] = {
NULL,
"SET_STREAM",
"SET_NV_TIMER",
"SET_BUTTON_PAGE",
"ENABLE_BUTTON",
"DISABLE_BUTTON",
"SET_SEC_STREAM",
"POPUP_OFF",
"STILL_ON",
"STILL_OFF",
"SET_OUTPUT_MODE",
"SET_STREAM_SS",
NULL,
NULL,
NULL,
NULL,
"[SETSYSTEM_0x10]",
};
static const char * const insn_opt_cmp[16] = {
NULL,
"bc",
"eq",
"ne",
"ge",
"gt",
"le",
"lt",
};
static const char * const insn_opt_goto[16] = {
"nop",
"goto",
"break",
};
static const char * const insn_opt_jump[16] = {
"JUMP_OBJECT",
"JUMP_TITLE",
"CALL_OBJECT",
"CALL_TITLE",
"RESUME"
};
static const char * const insn_opt_play[16] = {
"PLAY_PL",
"PLAY_PL_PI",
"PLAY_PL_MK",
"TERMINATE_PL",
"LINK_PI",
"LINK_MK"
};
static int _sprint_operand(char *buf, int imm, uint32_t op, int *psr)
{
char *start = buf;
if (!imm) {
if (op & 0x80000000) {
buf += sprintf(buf, "PSR%-3u", op & 0x7f);
*psr = op & 0x7f;
} else {
buf += sprintf(buf, "r%-5u", op & 0xfff);
}
} else {
if (op < 99999)
buf += sprintf(buf, "%-6u", op);
else
buf += sprintf(buf, "0x%-4x", op);
}
return buf - start;
}
static int _sprint_operands(char *buf, MOBJ_CMD *cmd)
{
char *start = buf;
HDMV_INSN *insn = &cmd->insn;
int psr1 = -1, psr2 = -1;
if (insn->op_cnt > 0) {
buf += _sprint_operand(buf, insn->imm_op1, cmd->dst, &psr1);
if (insn->op_cnt > 1) {
buf += sprintf(buf, ",\t");
buf += _sprint_operand(buf, insn->imm_op2, cmd->src, &psr2);
} else {
buf += sprintf(buf, " \t ");
}
} else {
buf += sprintf(buf, " \t ");
}
if (psr1 >= 0 && psr1 < 128 && psr_info[psr1])
buf += sprintf(buf, " %s", psr_info[psr1]);
if (psr2 >= 0 && psr2 < 128 && psr2 != psr1 && psr_info[psr2])
buf += sprintf(buf, " %s", psr_info[psr2]);
return buf - start;
}
static int _sprint_operands_hex(char *buf, MOBJ_CMD *cmd)
{
char *start = buf;
HDMV_INSN *insn = &cmd->insn;
if (insn->op_cnt > 0) {
buf += sprintf(buf, "0x%-4x", cmd->dst);
}
if (insn->op_cnt > 1) {
buf += sprintf(buf, ",\t0x%-4x", cmd->src);
}
return buf - start;
}
static uint32_t _cmd_to_u32(HDMV_INSN *insn)
{
union {
HDMV_INSN insn;
uint8_t u8[4];
} tmp;
tmp.insn = *insn;
return ((unsigned)tmp.u8[0] << 24) | (tmp.u8[1] << 16) | (tmp.u8[2] << 8) | tmp.u8[3];
}
int mobj_sprint_cmd(char *buf, MOBJ_CMD *cmd)
{
char *start = buf;
HDMV_INSN *insn = &cmd->insn;
buf += sprintf(buf, "%08x %08x,%08x ", _cmd_to_u32(&cmd->insn), cmd->dst, cmd->src);
switch(insn->grp) {
case INSN_GROUP_BRANCH:
switch(insn->sub_grp) {
case BRANCH_GOTO:
if (insn_opt_goto[insn->branch_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_goto[insn->branch_opt]);
buf += _sprint_operands(buf, cmd);
} else {
buf += sprintf(buf, "[unknown BRANCH/GOTO option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
case BRANCH_JUMP:
if (insn_opt_jump[insn->branch_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_jump[insn->branch_opt]);
buf += _sprint_operands(buf, cmd);
} else {
buf += sprintf(buf, "[unknown BRANCH/JUMP option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
case BRANCH_PLAY:
if (insn_opt_play[insn->branch_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_play[insn->branch_opt]);
buf += _sprint_operands(buf, cmd);
} else {
buf += sprintf(buf, "[unknown BRANCH/PLAY option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
default:
buf += sprintf(buf, "[unknown BRANCH subgroup in opcode 0x%08x] ", *(uint32_t*)insn);
break;
}
break;
case INSN_GROUP_CMP:
if (insn_opt_cmp[insn->cmp_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_cmp[insn->cmp_opt]);
buf += _sprint_operands(buf, cmd);
} else {
buf += sprintf(buf, "[unknown COMPARE option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
case INSN_GROUP_SET:
switch (insn->sub_grp) {
case SET_SET:
if (insn_opt_set[insn->set_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_set[insn->set_opt]);
buf += _sprint_operands(buf, cmd);
} else {
buf += sprintf(buf, "[unknown SET option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
case SET_SETSYSTEM:
if (insn_opt_setsys[insn->set_opt]) {
buf += sprintf(buf, "%-10s ", insn_opt_setsys[insn->set_opt]);
if (insn->set_opt == INSN_SET_STREAM ||
insn->set_opt == INSN_SET_SEC_STREAM ||
insn->set_opt == INSN_SET_BUTTON_PAGE) {
buf += _sprint_operands_hex(buf, cmd);
} else {
buf += _sprint_operands(buf, cmd);
}
} else {
buf += sprintf(buf, "[unknown SETSYSTEM option in opcode 0x%08x] ", *(uint32_t*)insn);
}
break;
default:
buf += sprintf(buf, "[unknown SET subgroup in opcode 0x%08x] ", *(uint32_t*)insn);
break;
}
break;
default:
buf += sprintf(buf, "[unknown group in opcode 0x%08x] ", *(uint32_t*)insn);
break;
}
return buf - start;
}