|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010-2017 Petri Hintukainen <phintuka@users.sourceforge.net>
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if HAVE_CONFIG_H
|
|
Packit |
5e46da |
#include "config.h"
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "hdmv_vm.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "mobj_data.h"
|
|
Packit |
5e46da |
#include "hdmv_insn.h"
|
|
Packit |
5e46da |
#include "mobj_parse.h"
|
|
Packit |
5e46da |
#include "mobj_print.h"
|
|
Packit |
5e46da |
#include "../register.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
#include "util/logging.h"
|
|
Packit |
5e46da |
#include "util/mutex.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdio.h>
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
#include <time.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
typedef struct {
|
|
Packit |
5e46da |
time_t time;
|
|
Packit |
5e46da |
uint32_t mobj_id;
|
|
Packit |
5e46da |
} NV_TIMER;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
struct hdmv_vm_s {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_MUTEX mutex;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* state */
|
|
Packit |
5e46da |
uint32_t pc; /* program counter */
|
|
Packit |
5e46da |
BD_REGISTERS *regs; /* player registers */
|
|
Packit |
5e46da |
const MOBJ_OBJECT *object; /* currently running object code */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
HDMV_EVENT event[5]; /* pending events to return */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
NV_TIMER nv_timer; /* navigation timer */
|
|
Packit |
5e46da |
uint64_t rand; /* RAND state */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* movie objects */
|
|
Packit |
5e46da |
MOBJ_OBJECTS *movie_objects; /* disc movie objects */
|
|
Packit |
5e46da |
MOBJ_OBJECT *ig_object; /* current object from IG stream */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* object currently playing playlist */
|
|
Packit |
5e46da |
const MOBJ_OBJECT *playing_object;
|
|
Packit |
5e46da |
uint32_t playing_pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* suspended object */
|
|
Packit |
5e46da |
const MOBJ_OBJECT *suspended_object;
|
|
Packit |
5e46da |
uint32_t suspended_pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* Available titles. Used to validate CALL_TITLE/JUMP_TITLE. */
|
|
Packit |
5e46da |
uint8_t have_top_menu;
|
|
Packit |
5e46da |
uint8_t have_first_play;
|
|
Packit |
5e46da |
uint16_t num_titles;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* save / restore VM state
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _save_state(HDMV_VM *p, uint32_t *s)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
memset(s, 0, sizeof(*s) * HDMV_STATE_SIZE);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_save_state() failed: button object running\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (p->object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_save_state() failed: movie object running\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (p->event[0].event != HDMV_EVENT_NONE) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_save_state() failed: unprocessed events\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->playing_object) {
|
|
Packit |
5e46da |
s[0] = (uint32_t)(p->playing_object - p->movie_objects->objects);
|
|
Packit |
5e46da |
s[1] = p->playing_pc;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
s[0] = (uint32_t)-1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->suspended_object) {
|
|
Packit |
5e46da |
s[2] = (uint32_t)(p->suspended_object - p->movie_objects->objects);
|
|
Packit |
5e46da |
s[3] = p->suspended_pc;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
s[2] = (uint32_t)-1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* nv timer ? */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _restore_state(HDMV_VM *p, const uint32_t *s)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (s[0] == (uint32_t)-1) {
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
} else if (s[0] >= p->movie_objects->num_objects) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_restore_state() failed: invalid playing object index\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
p->playing_object = &p->movie_objects->objects[s[0]];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->playing_pc = s[1];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (s[2] == (uint32_t)-1) {
|
|
Packit |
5e46da |
p->suspended_object = NULL;
|
|
Packit |
5e46da |
} else if (s[2] >= p->movie_objects->num_objects) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_restore_state() failed: invalid suspended object index\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
p->suspended_object = &p->movie_objects->objects[s[2]];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->suspended_pc = s[3];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
p->ig_object = NULL;
|
|
Packit |
5e46da |
memset(p->event, 0, sizeof(p->event));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_save_state(HDMV_VM *p, uint32_t *s)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
result = _save_state(p, s);
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void hdmv_vm_restore_state(HDMV_VM *p, const uint32_t *s)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
_restore_state(p, s);
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* registers: PSR and GPR access
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define PSR_FLAG 0x80000000
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _is_valid_reg(uint32_t reg)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (reg & PSR_FLAG) {
|
|
Packit |
5e46da |
if (reg & ~0x8000007f) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (reg & ~0x00000fff) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _store_reg(HDMV_VM *p, uint32_t reg, uint32_t val)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!_is_valid_reg(reg)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_store_reg(): invalid register 0x%x\n", reg);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (reg & PSR_FLAG) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_store_reg(): storing to PSR is not allowed\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
return bd_gpr_write(p->regs, reg, val);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t _read_reg(HDMV_VM *p, uint32_t reg)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!_is_valid_reg(reg)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_read_reg(): invalid register 0x%x\n", reg);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (reg & PSR_FLAG) {
|
|
Packit |
5e46da |
return bd_psr_read(p->regs, reg & 0x7f);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
return bd_gpr_read(p->regs, reg);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t _read_setstream_regs(HDMV_VM *p, uint32_t val)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t flags = val & 0xf000f000;
|
|
Packit |
5e46da |
uint32_t reg0 = val & 0xfff;
|
|
Packit |
5e46da |
uint32_t reg1 = (val >> 16) & 0xfff;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t val0 = bd_gpr_read(p->regs, reg0) & 0x0fff;
|
|
Packit |
5e46da |
uint32_t val1 = bd_gpr_read(p->regs, reg1) & 0x0fff;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return flags | val0 | (val1 << 16);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t _read_setbuttonpage_reg(HDMV_VM *p, uint32_t val)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t flags = val & 0xc0000000;
|
|
Packit |
5e46da |
uint32_t reg0 = val & 0x00000fff;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t val0 = bd_gpr_read(p->regs, reg0) & 0x3fffffff;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return flags | val0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _store_result(HDMV_VM *p, MOBJ_CMD *cmd, uint32_t src, uint32_t dst, uint32_t src0, uint32_t dst0)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int ret = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* store result to destination register(s) */
|
|
Packit |
5e46da |
if (dst != dst0) {
|
|
Packit |
5e46da |
if (cmd->insn.imm_op1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "storing to imm !\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
ret = _store_reg(p, cmd->dst, dst);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (src != src0) {
|
|
Packit |
5e46da |
if (cmd->insn.imm_op1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "storing to imm !\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
ret += _store_reg(p, cmd->src, src);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return ret;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t _fetch_operand(HDMV_VM *p, int setstream, int setbuttonpage, int imm, uint32_t value)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (imm) {
|
|
Packit |
5e46da |
return value;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (setstream) {
|
|
Packit |
5e46da |
return _read_setstream_regs(p, value);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else if (setbuttonpage) {
|
|
Packit |
5e46da |
return _read_setbuttonpage_reg(p, value);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
return _read_reg(p, value);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _fetch_operands(HDMV_VM *p, MOBJ_CMD *cmd, uint32_t *dst, uint32_t *src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
HDMV_INSN *insn = &cmd->insn;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int setstream = (insn->grp == INSN_GROUP_SET &&
|
|
Packit |
5e46da |
insn->sub_grp == SET_SETSYSTEM &&
|
|
Packit |
5e46da |
( insn->set_opt == INSN_SET_STREAM ||
|
|
Packit |
5e46da |
insn->set_opt == INSN_SET_SEC_STREAM));
|
|
Packit |
5e46da |
int setbuttonpage = (insn->grp == INSN_GROUP_SET &&
|
|
Packit |
5e46da |
insn->sub_grp == SET_SETSYSTEM &&
|
|
Packit |
5e46da |
insn->set_opt == INSN_SET_BUTTON_PAGE);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*dst = *src = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (insn->op_cnt > 0) {
|
|
Packit |
5e46da |
*dst = _fetch_operand(p, setstream, setbuttonpage, insn->imm_op1, cmd->dst);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (insn->op_cnt > 1) {
|
|
Packit |
5e46da |
*src = _fetch_operand(p, setstream, setbuttonpage, insn->imm_op2, cmd->src);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* event queue
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _get_event(HDMV_VM *p, HDMV_EVENT *ev)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->event[0].event != HDMV_EVENT_NONE) {
|
|
Packit |
5e46da |
*ev = p->event[0];
|
|
Packit |
5e46da |
memmove(p->event, p->event + 1, sizeof(p->event) - sizeof(p->event[0]));
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
ev->event = HDMV_EVENT_NONE;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _queue_event(HDMV_VM *p, hdmv_event_e event, uint32_t param)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned i;
|
|
Packit |
5e46da |
for (i = 0; i < sizeof(p->event) / sizeof(p->event[0]) - 1; i++) {
|
|
Packit |
5e46da |
if (p->event[i].event == HDMV_EVENT_NONE) {
|
|
Packit |
5e46da |
p->event[i].event = event;
|
|
Packit |
5e46da |
p->event[i].param = param;
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_queue_event(%d, %d): queue overflow !\n", event, param);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* vm init
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
HDMV_VM *hdmv_vm_init(struct bd_disc *disc, BD_REGISTERS *regs,
|
|
Packit |
5e46da |
unsigned num_titles, unsigned first_play_available, unsigned top_menu_available)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
HDMV_VM *p = calloc(1, sizeof(HDMV_VM));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* read movie objects */
|
|
Packit |
5e46da |
p->movie_objects = mobj_get(disc);
|
|
Packit |
5e46da |
if (!p->movie_objects) {
|
|
Packit |
5e46da |
X_FREE(p);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->regs = regs;
|
|
Packit |
5e46da |
p->num_titles = num_titles;
|
|
Packit |
5e46da |
p->have_top_menu = top_menu_available;
|
|
Packit |
5e46da |
p->have_first_play = first_play_available;
|
|
Packit |
5e46da |
#ifdef DEBUG
|
|
Packit |
5e46da |
p->rand = 1;
|
|
Packit |
5e46da |
#else
|
|
Packit |
5e46da |
p->rand = time(NULL);
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_init(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return p;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _free_ig_object(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
X_FREE(p->ig_object->cmds);
|
|
Packit |
5e46da |
X_FREE(p->ig_object);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void hdmv_vm_free(HDMV_VM **p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p && *p) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_destroy(&(*p)->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
mobj_free(&(*p)->movie_objects);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_free_ig_object(*p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(*p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* suspend/resume ("function call")
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _suspended_at_play_pl(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int play_pl = 0;
|
|
Packit |
5e46da |
if (p && p->suspended_object) {
|
|
Packit |
5e46da |
MOBJ_CMD *cmd = &p->suspended_object->cmds[p->suspended_pc];
|
|
Packit |
5e46da |
HDMV_INSN *insn = &cmd->insn;
|
|
Packit |
5e46da |
play_pl = (insn->grp == INSN_GROUP_BRANCH &&
|
|
Packit |
5e46da |
insn->sub_grp == BRANCH_PLAY &&
|
|
Packit |
5e46da |
( insn->branch_opt == INSN_PLAY_PL ||
|
|
Packit |
5e46da |
insn->branch_opt == INSN_PLAY_PL_PI ||
|
|
Packit |
5e46da |
insn->branch_opt == INSN_PLAY_PL_PM));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return play_pl;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _suspend_for_play_pl(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->playing_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_for_play_pl(): object already playing playlist !\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = p->object;
|
|
Packit |
5e46da |
p->playing_pc = p->pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _resume_from_play_pl(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!p->playing_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_resume_from_play_pl(): object not playing playlist !\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = p->playing_object;
|
|
Packit |
5e46da |
p->pc = p->playing_pc + 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _suspend_object(HDMV_VM *p, int psr_backup)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_suspend_object()\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->suspended_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_suspend_object: object already suspended !\n");
|
|
Packit |
5e46da |
// [execute the call, discard old suspended object (10.2.4.2.2)].
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (psr_backup) {
|
|
Packit |
5e46da |
bd_psr_save_state(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
if (!p->playing_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_object: IG object tries to suspend, no playing object !\n");
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->suspended_object = p->playing_object;
|
|
Packit |
5e46da |
p->suspended_pc = p->playing_pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->playing_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_object: Movie object tries to suspend, also playing object present !\n");
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->suspended_object = p->object;
|
|
Packit |
5e46da |
p->suspended_pc = p->pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _resume_object(HDMV_VM *p, int psr_restore)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!p->suspended_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_resume_object: no suspended object!\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (psr_restore) {
|
|
Packit |
5e46da |
/* check if suspended in play_pl */
|
|
Packit |
5e46da |
if (_suspended_at_play_pl(p)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "resuming playlist playback\n");
|
|
Packit |
5e46da |
p->playing_object = p->suspended_object;
|
|
Packit |
5e46da |
p->playing_pc = p->suspended_pc;
|
|
Packit |
5e46da |
p->suspended_object = NULL;
|
|
Packit |
5e46da |
bd_psr_restore_state(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bd_psr_restore_state(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = p->suspended_object;
|
|
Packit |
5e46da |
p->pc = p->suspended_pc + 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->suspended_object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "resuming object %ld at %d\n",
|
|
Packit |
5e46da |
(long)(p->object - p->movie_objects->objects),
|
|
Packit |
5e46da |
p->pc);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* branching
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _is_valid_title(HDMV_VM *p, uint32_t title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (title == 0) {
|
|
Packit |
5e46da |
return p->have_top_menu;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (title == 0xffff) {
|
|
Packit |
5e46da |
return p->have_first_play;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return title > 0 && title <= p->num_titles;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _jump_object(HDMV_VM *p, uint32_t object)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (object >= p->movie_objects->num_objects) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_jump_object(): invalid object %u\n", object);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_jump_object(): jumping to object %u\n", object);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->pc = 0;
|
|
Packit |
5e46da |
p->object = &p->movie_objects->objects[object];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* suspended object is not discarded */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _jump_title(HDMV_VM *p, uint32_t title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (_is_valid_title(p, title)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_jump_title(%u)\n", title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* discard suspended object */
|
|
Packit |
5e46da |
p->suspended_object = NULL;
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
bd_psr_reset_backup_registers(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_TITLE, title);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_jump_title(%u): invalid title number\n", title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _call_object(HDMV_VM *p, uint32_t object)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (object >= p->movie_objects->num_objects) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_call_object(): invalid object %u\n", object);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_call_object(%u)\n", object);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_suspend_object(p, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return _jump_object(p, object);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _call_title(HDMV_VM *p, uint32_t title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (_is_valid_title(p, title)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_call_title(%u)\n", title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_suspend_object(p, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_TITLE, title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_call_title(%u): invalid title number\n", title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* playback control
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _play_at(HDMV_VM *p, int playlist, int playitem, int playmark)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->ig_object && playlist >= 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "play_at(list %d, item %d, mark %d): "
|
|
Packit |
5e46da |
"playlist change not allowed in interactive composition\n",
|
|
Packit |
5e46da |
playlist, playitem, playmark);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p->ig_object && playlist < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "play_at(list %d, item %d, mark %d): "
|
|
Packit |
5e46da |
"playlist not given in movie object (link commands not allowed)\n",
|
|
Packit |
5e46da |
playlist, playitem, playmark);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "play_at(list %d, item %d, mark %d)\n",
|
|
Packit |
5e46da |
playlist, playitem, playmark);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (playlist >= 0) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_PL, playlist);
|
|
Packit |
5e46da |
_suspend_for_play_pl(p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (playitem >= 0) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_PI, playitem);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (playmark >= 0) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_PM, playmark);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _play_stop(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!p->ig_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_play_stop() not allowed in movie object\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_play_stop()\n");
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_PLAY_STOP, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* terminate IG object. Continue executing movie object. */
|
|
Packit |
5e46da |
if (_resume_from_play_pl(p) < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_play_stop(): resuming movie object failed !\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* SET/SYSTEM setstream
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_stream(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_stream(0x%x, 0x%x)\n", dst, src);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* primary audio stream */
|
|
Packit |
5e46da |
if (dst & 0x80000000) {
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_PRIMARY_AUDIO_ID, (dst >> 16) & 0xfff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* IG stream */
|
|
Packit |
5e46da |
if (src & 0x80000000) {
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_IG_STREAM_ID, (src >> 16) & 0xff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* angle number */
|
|
Packit |
5e46da |
if (src & 0x8000) {
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_ANGLE_NUMBER, src & 0xff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* PSR2 */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_lock(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t psr2 = bd_psr_read(p->regs, PSR_PG_STREAM);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* PG TextST stream number */
|
|
Packit |
5e46da |
if (dst & 0x8000) {
|
|
Packit |
5e46da |
uint32_t text_st_num = dst & 0xfff;
|
|
Packit |
5e46da |
psr2 = text_st_num | (psr2 & 0xfffff000);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* Update PG TextST stream display flag */
|
|
Packit |
5e46da |
uint32_t disp_s_flag = (dst & 0x4000) << 17;
|
|
Packit |
5e46da |
psr2 = disp_s_flag | (psr2 & 0x7fffffff);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_PG_STREAM, psr2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_unlock(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_sec_stream(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_sec_stream(0x%x, 0x%x)\n", dst, src);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t disp_v_flag = (dst >> 30) & 1;
|
|
Packit |
5e46da |
uint32_t disp_a_flag = (src >> 30) & 1;
|
|
Packit |
5e46da |
uint32_t text_st_flags = (src >> 13) & 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* PSR14 */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_lock(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t psr14 = bd_psr_read(p->regs, PSR_SECONDARY_AUDIO_VIDEO);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* secondary video */
|
|
Packit |
5e46da |
if (dst & 0x80000000) {
|
|
Packit |
5e46da |
uint32_t sec_video = dst & 0xff;
|
|
Packit |
5e46da |
psr14 = (sec_video << 8) | (psr14 & 0xffff00ff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* secondary video size */
|
|
Packit |
5e46da |
if (dst & 0x00800000) {
|
|
Packit |
5e46da |
uint32_t video_size = (dst >> 16) & 0xf;
|
|
Packit |
5e46da |
psr14 = (video_size << 24) | (psr14 & 0xf0ffffff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* secondary audio */
|
|
Packit |
5e46da |
if (src & 0x80000000) {
|
|
Packit |
5e46da |
uint32_t sec_audio = (src >> 16) & 0xff;
|
|
Packit |
5e46da |
psr14 = sec_audio | (psr14 & 0xffffff00);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
psr14 = (disp_v_flag << 31) | (psr14 & 0x7fffffff);
|
|
Packit |
5e46da |
psr14 = (disp_a_flag << 30) | (psr14 & 0xbfffffff);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_SECONDARY_AUDIO_VIDEO, psr14);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* PSR2 */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t psr2 = bd_psr_read(p->regs, PSR_PG_STREAM);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* PiP PG TextST stream */
|
|
Packit |
5e46da |
if (src & 0x8000) {
|
|
Packit |
5e46da |
uint32_t stream = src & 0xfff;
|
|
Packit |
5e46da |
psr2 = (stream << 16) | (psr2 & 0xf000ffff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
psr2 = (text_st_flags << 30) | (psr2 & 0x3fffffff);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_PG_STREAM, psr2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_unlock(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_stream_ss(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_stream_ss(0x%x, 0x%x)\n", dst, src);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!(bd_psr_read(p->regs, PSR_3D_STATUS) & 1)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_stream_ss ignored (PSR22 indicates 2D mode)\n");
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_stream_ss(0x%x, 0x%x) unimplemented\n", dst, src);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _setsystem_0x10(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_psr103(0x%x, 0x%x)\n", dst, src);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_lock(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* just a guess ... */
|
|
Packit |
5e46da |
//bd_psr_write(p->regs, 104, 0);
|
|
Packit |
5e46da |
bd_psr_write(p->regs, 103, dst);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_unlock(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* SET/SYSTEM navigation control
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_button_page(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
uint32_t param;
|
|
Packit |
5e46da |
param = (src & 0xc0000000) | /* page and effects flags */
|
|
Packit |
5e46da |
((dst & 0x80000000) >> 2) | /* button flag */
|
|
Packit |
5e46da |
((src & 0x000000ff) << 16) | /* page id */
|
|
Packit |
5e46da |
(dst & 0x0000ffff); /* button id */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_SET_BUTTON_PAGE, param);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* terminate */
|
|
Packit |
5e46da |
p->pc = 1 << 17;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* selected button */
|
|
Packit |
5e46da |
if (dst & 0x80000000) {
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_SELECTED_BUTTON_ID, dst & 0xffff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* active page */
|
|
Packit |
5e46da |
if (src & 0x80000000) {
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_MENU_PAGE_ID, src & 0xff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _enable_button(HDMV_VM *p, uint32_t dst, int enable)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/* not valid in movie objects */
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
if (enable) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_ENABLE_BUTTON, dst);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_DISABLE_BUTTON, dst);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_still_mode(HDMV_VM *p, int enable)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/* not valid in movie objects */
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_STILL, enable);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _popup_off(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/* not valid in movie objects */
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
_queue_event(p, HDMV_EVENT_POPUP_OFF, 1);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* SET/SYSTEM 3D mode
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_output_mode(HDMV_VM *p, uint32_t dst)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if ((bd_psr_read(p->regs, PSR_PROFILE_VERSION) & 0x130240) != 0x130240) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "_set_output_mode ignored (not running as profile 5 player)\n");
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_lock(p->regs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t psr22 = bd_psr_read(p->regs, PSR_3D_STATUS);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* update output mode (bit 0). PSR22 bits 1 and 2 are subtitle alignment (_set_stream_ss()) */
|
|
Packit |
5e46da |
if (dst & 1) {
|
|
Packit |
5e46da |
psr22 |= 1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
psr22 &= ~1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_3D_STATUS, psr22);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_unlock(p->regs);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* navigation timer
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _set_nv_timer(HDMV_VM *p, uint32_t dst, uint32_t src)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t mobj_id = dst & 0xffff;
|
|
Packit |
5e46da |
uint32_t timeout = src & 0xffff;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!timeout) {
|
|
Packit |
5e46da |
/* cancel timer */
|
|
Packit |
5e46da |
p->nv_timer.time = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_NAV_TIMER, 0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* validate params */
|
|
Packit |
5e46da |
if (mobj_id >= p->movie_objects->num_objects) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_set_nv_timer(): invalid object id (%d) !\n", mobj_id);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (timeout > 300) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "_set_nv_timer(): invalid timeout (%d) !\n", timeout);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV | DBG_CRIT, "_set_nv_timer(): navigation timer not implemented !\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* set expiration time */
|
|
Packit |
5e46da |
p->nv_timer.time = time(NULL);
|
|
Packit |
5e46da |
p->nv_timer.time += timeout;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->nv_timer.mobj_id = mobj_id;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_NAV_TIMER, timeout);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* Unused function.
|
|
Packit |
5e46da |
* Commenting out to disable "‘_check_nv_timer’ defined but not used" warning
|
|
Packit |
5e46da |
static int _check_nv_timer(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p->nv_timer.time > 0) {
|
|
Packit |
5e46da |
time_t now = time(NULL);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (now >= p->nv_timer.time) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "navigation timer expired, jumping to object %d\n", p->nv_timer.mobj_id);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_NAV_TIMER, 0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->nv_timer.time = 0;
|
|
Packit |
5e46da |
_jump_object(p, p->nv_timer.mobj_id);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_write(p->regs, PSR_NAV_TIMER, (p->nv_timer.time - now));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* trace
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _hdmv_trace_cmd(int pc, MOBJ_CMD *cmd)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (bd_get_debug_mask() & DBG_HDMV) {
|
|
Packit |
5e46da |
char buf[384], *dst = buf;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dst += sprintf(dst, "%04d: ", pc);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*dst +=*/ mobj_sprint_cmd(dst, cmd);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "%s\n", buf);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _hdmv_trace_res(uint32_t new_src, uint32_t new_dst, uint32_t orig_src, uint32_t orig_dst)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (bd_get_debug_mask() & DBG_HDMV) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (new_dst != orig_dst || new_src != orig_src) {
|
|
Packit |
5e46da |
char buf[384], *dst = buf;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dst += sprintf(dst, " : [");
|
|
Packit |
5e46da |
if (new_dst != orig_dst) {
|
|
Packit |
5e46da |
dst += sprintf(dst, " dst 0x%x <== 0x%x ", orig_dst, new_dst);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (new_src != orig_src) {
|
|
Packit |
5e46da |
dst += sprintf(dst, " src 0x%x <== 0x%x ", orig_src, new_src);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
/*dst +=*/ sprintf(dst, "]");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "%s\n", buf);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* interpreter
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* tools
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define SWAP_u32(a, b) do { uint32_t tmp = a; a = b; b = tmp; } while(0)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static inline uint32_t RAND_u32(HDMV_VM *p, uint32_t range)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
p->rand = p->rand * UINT64_C(6364136223846793005) + UINT64_C(1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (range == 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "RAND_u32: invalid range (0)\n");
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return ((uint32_t)(p->rand >> 32)) % range + 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static inline uint32_t ADD_u32(uint32_t a, uint32_t b)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/* overflow -> saturate */
|
|
Packit |
5e46da |
uint64_t result = (uint64_t)a + b;
|
|
Packit |
5e46da |
return result < 0xffffffff ? (uint32_t)result : 0xffffffff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static inline uint32_t MUL_u32(uint32_t a, uint32_t b)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/* overflow -> saturate */
|
|
Packit |
5e46da |
uint64_t result = (uint64_t)a * b;
|
|
Packit |
5e46da |
return result < 0xffffffff ? (uint32_t)result : 0xffffffff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* _hdmv_step()
|
|
Packit |
5e46da |
* - execute next instruction from current program
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
static int _hdmv_step(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MOBJ_CMD *cmd = &p->object->cmds[p->pc];
|
|
Packit |
5e46da |
HDMV_INSN *insn = &cmd->insn;
|
|
Packit |
5e46da |
uint32_t src = 0;
|
|
Packit |
5e46da |
uint32_t dst = 0;
|
|
Packit |
5e46da |
int inc_pc = 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* fetch operand values */
|
|
Packit |
5e46da |
_fetch_operands(p, cmd, &dst, &src;;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* trace */
|
|
Packit |
5e46da |
_hdmv_trace_cmd(p->pc, cmd);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* execute */
|
|
Packit |
5e46da |
switch (insn->grp) {
|
|
Packit |
5e46da |
case INSN_GROUP_BRANCH:
|
|
Packit |
5e46da |
switch (insn->sub_grp) {
|
|
Packit |
5e46da |
case BRANCH_GOTO:
|
|
Packit |
5e46da |
if (insn->op_cnt > 1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "too many operands in BRANCH/GOTO opcode 0x%08x\n", *(uint32_t*)insn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
switch (insn->branch_opt) {
|
|
Packit |
5e46da |
case INSN_NOP: break;
|
|
Packit |
5e46da |
case INSN_GOTO: p->pc = dst - 1; break;
|
|
Packit |
5e46da |
case INSN_BREAK: p->pc = 1 << 17; break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown BRANCH/GOTO option %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->branch_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case BRANCH_JUMP:
|
|
Packit |
5e46da |
if (insn->op_cnt > 1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "too many operands in BRANCH/JUMP opcode 0x%08x\n", *(uint32_t*)insn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
switch (insn->branch_opt) {
|
|
Packit |
5e46da |
case INSN_JUMP_TITLE: _jump_title(p, dst); break;
|
|
Packit |
5e46da |
case INSN_CALL_TITLE: _call_title(p, dst); break;
|
|
Packit |
5e46da |
case INSN_RESUME: _resume_object(p, 1); break;
|
|
Packit |
5e46da |
case INSN_JUMP_OBJECT: if (!_jump_object(p, dst)) { inc_pc = 0; } break;
|
|
Packit |
5e46da |
case INSN_CALL_OBJECT: if (!_call_object(p, dst)) { inc_pc = 0; } break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown BRANCH/JUMP option %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->branch_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case BRANCH_PLAY:
|
|
Packit |
5e46da |
switch (insn->branch_opt) {
|
|
Packit |
5e46da |
case INSN_PLAY_PL: _play_at(p, dst, -1, -1); break;
|
|
Packit |
5e46da |
case INSN_PLAY_PL_PI: _play_at(p, dst, src, -1); break;
|
|
Packit |
5e46da |
case INSN_PLAY_PL_PM: _play_at(p, dst, -1, src); break;
|
|
Packit |
5e46da |
case INSN_LINK_PI: _play_at(p, -1, dst, -1); break;
|
|
Packit |
5e46da |
case INSN_LINK_MK: _play_at(p, -1, -1, dst); break;
|
|
Packit |
5e46da |
case INSN_TERMINATE_PL: if (!_play_stop(p)) { inc_pc = 0; } break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown BRANCH/PLAY option %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->branch_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown BRANCH subgroup %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->sub_grp, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break; /* INSN_GROUP_BRANCH */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case INSN_GROUP_CMP:
|
|
Packit |
5e46da |
if (insn->op_cnt < 2) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "missing operand in BRANCH/JUMP opcode 0x%08x\n", *(uint32_t*)insn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
switch (insn->cmp_opt) {
|
|
Packit |
5e46da |
case INSN_BC: p->pc += !!(dst & ~src); break;
|
|
Packit |
5e46da |
case INSN_EQ: p->pc += !(dst == src); break;
|
|
Packit |
5e46da |
case INSN_NE: p->pc += !(dst != src); break;
|
|
Packit |
5e46da |
case INSN_GE: p->pc += !(dst >= src); break;
|
|
Packit |
5e46da |
case INSN_GT: p->pc += !(dst > src); break;
|
|
Packit |
5e46da |
case INSN_LE: p->pc += !(dst <= src); break;
|
|
Packit |
5e46da |
case INSN_LT: p->pc += !(dst < src); break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown COMPARE option %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->cmp_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break; /* INSN_GROUP_CMP */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case INSN_GROUP_SET:
|
|
Packit |
5e46da |
switch (insn->sub_grp) {
|
|
Packit |
5e46da |
case SET_SET: {
|
|
Packit |
5e46da |
uint32_t src0 = src;
|
|
Packit |
5e46da |
uint32_t dst0 = dst;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (insn->op_cnt < 2) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "missing operand in SET/SET opcode 0x%08x\n", *(uint32_t*)insn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
switch (insn->set_opt) {
|
|
Packit |
5e46da |
case INSN_MOVE: dst = src; break;
|
|
Packit |
5e46da |
case INSN_SWAP: SWAP_u32(src, dst); break;
|
|
Packit |
5e46da |
case INSN_SUB: dst = dst > src ? dst - src : 0; break;
|
|
Packit |
5e46da |
case INSN_DIV: dst = src > 0 ? dst / src : 0xffffffff; break;
|
|
Packit |
5e46da |
case INSN_MOD: dst = src > 0 ? dst % src : 0xffffffff; break;
|
|
Packit |
5e46da |
case INSN_ADD: dst = ADD_u32(src, dst); break;
|
|
Packit |
5e46da |
case INSN_MUL: dst = MUL_u32(dst, src); break;
|
|
Packit |
5e46da |
case INSN_RND: dst = RAND_u32(p, src); break;
|
|
Packit |
5e46da |
case INSN_AND: dst &= src; break;
|
|
Packit |
5e46da |
case INSN_OR: dst |= src; break;
|
|
Packit |
5e46da |
case INSN_XOR: dst ^= src; break;
|
|
Packit |
5e46da |
case INSN_BITSET: dst |= (1 << src); break;
|
|
Packit |
5e46da |
case INSN_BITCLR: dst &= ~(1 << src); break;
|
|
Packit |
5e46da |
case INSN_SHL: dst <<= src; break;
|
|
Packit |
5e46da |
case INSN_SHR: dst >>= src; break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown SET option %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->set_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* store result(s) */
|
|
Packit |
5e46da |
if (dst != dst0 || src != src0) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_hdmv_trace_res(src, dst, src0, dst0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_store_result(p, cmd, src, dst, src0, dst0);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
case SET_SETSYSTEM:
|
|
Packit |
5e46da |
switch (insn->set_opt) {
|
|
Packit |
5e46da |
case INSN_SET_STREAM: _set_stream (p, dst, src); break;
|
|
Packit |
5e46da |
case INSN_SET_SEC_STREAM: _set_sec_stream (p, dst, src); break;
|
|
Packit |
5e46da |
case INSN_SET_NV_TIMER: _set_nv_timer (p, dst, src); break;
|
|
Packit |
5e46da |
case INSN_SET_BUTTON_PAGE: _set_button_page(p, dst, src); break;
|
|
Packit |
5e46da |
case INSN_ENABLE_BUTTON: _enable_button (p, dst, 1); break;
|
|
Packit |
5e46da |
case INSN_DISABLE_BUTTON: _enable_button (p, dst, 0); break;
|
|
Packit |
5e46da |
case INSN_POPUP_OFF: _popup_off (p); break;
|
|
Packit |
5e46da |
case INSN_STILL_ON: _set_still_mode (p, 1); break;
|
|
Packit |
5e46da |
case INSN_STILL_OFF: _set_still_mode (p, 0); break;
|
|
Packit |
5e46da |
case INSN_SET_OUTPUT_MODE: _set_output_mode(p, dst); break;
|
|
Packit |
5e46da |
case INSN_SET_STREAM_SS: _set_stream_ss (p, dst, src); break;
|
|
Packit |
5e46da |
case INSN_SETSYSTEM_0x10: _setsystem_0x10 (p, dst, src); break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown SETSYSTEM option %d in opcode 0x%08x\n", insn->set_opt, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown SET subgroup %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->sub_grp, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break; /* INSN_GROUP_SET */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "unknown operation group %d in opcode 0x%08x\n",
|
|
Packit |
5e46da |
insn->grp, *(uint32_t*)insn);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* inc program counter to next instruction */
|
|
Packit |
5e46da |
p->pc += inc_pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* interface
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_select_object(HDMV_VM *p, uint32_t object)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = _jump_object(p, object);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _set_object(HDMV_VM *p, int num_nav_cmds, void *nav_cmds)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MOBJ_OBJECT *ig_object = calloc(1, sizeof(MOBJ_OBJECT));
|
|
Packit |
5e46da |
if (!ig_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
ig_object->num_cmds = num_nav_cmds;
|
|
Packit |
5e46da |
ig_object->cmds = calloc(num_nav_cmds, sizeof(MOBJ_CMD));
|
|
Packit |
5e46da |
if (!ig_object->cmds) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
X_FREE(ig_object);
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
memcpy(ig_object->cmds, nav_cmds, num_nav_cmds * sizeof(MOBJ_CMD));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->pc = 0;
|
|
Packit |
5e46da |
p->ig_object = ig_object;
|
|
Packit |
5e46da |
p->object = ig_object;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_set_object(HDMV_VM *p, int num_nav_cmds, void *nav_cmds)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result = -1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (nav_cmds && num_nav_cmds > 0) {
|
|
Packit |
5e46da |
result = _set_object(p, num_nav_cmds, nav_cmds);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_get_event(HDMV_VM *p, HDMV_EVENT *ev)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = _get_event(p, ev);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_running(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = !!p->object;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t hdmv_vm_get_uo_mask(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t mask = 0;
|
|
Packit |
5e46da |
const MOBJ_OBJECT *o = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((o = (p->object && !p->ig_object) ? p->object : (p->playing_object ? p->playing_object : p->suspended_object))) {
|
|
Packit |
5e46da |
mask |= o->menu_call_mask;
|
|
Packit |
5e46da |
mask |= o->title_search_mask << 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return mask;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_resume(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = _resume_from_play_pl(p);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_suspend_pl(HDMV_VM *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result = -1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->object || p->ig_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): HDMV VM is still running\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else if (!p->playing_object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): No playing object\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else if (!p->playing_object->resume_intention_flag) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): no resume intention flag\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
result = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
p->suspended_object = p->playing_object;
|
|
Packit |
5e46da |
p->suspended_pc = p->playing_pc;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->playing_object = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_psr_save_state(p->regs);
|
|
Packit |
5e46da |
result = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* terminate program after MAX_LOOP instructions */
|
|
Packit |
5e46da |
#define MAX_LOOP 1000000
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _vm_run(HDMV_VM *p, HDMV_EVENT *ev)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int max_loop = MAX_LOOP;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* pending events ? */
|
|
Packit |
5e46da |
if (!_get_event(p, ev)) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* valid program ? */
|
|
Packit |
5e46da |
if (!p->object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "hdmv_vm_run(): no object selected\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
while (--max_loop > 0) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* suspended ? */
|
|
Packit |
5e46da |
if (!p->object) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "hdmv_vm_run(): object suspended\n");
|
|
Packit |
5e46da |
_get_event(p, ev);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* terminated ? */
|
|
Packit |
5e46da |
if (p->pc >= p->object->num_cmds) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV, "terminated with PC=%d\n", p->pc);
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
ev->event = HDMV_EVENT_END;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->ig_object) {
|
|
Packit |
5e46da |
ev->event = HDMV_EVENT_IG_END;
|
|
Packit |
5e46da |
_free_ig_object(p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* next instruction */
|
|
Packit |
5e46da |
if (_hdmv_step(p) < 0) {
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* events ? */
|
|
Packit |
5e46da |
if (!_get_event(p, ev)) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "hdmv_vm: infinite program ? terminated after %d instructions.\n", MAX_LOOP);
|
|
Packit |
5e46da |
p->object = NULL;
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int hdmv_vm_run(HDMV_VM *p, HDMV_EVENT *ev)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_lock(&p->mutex);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = _vm_run(p, ev);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bd_mutex_unlock(&p->mutex);
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|