📄 util.c
字号:
/* Copyright 1996-1997, ESS Technology, Inc. */
/* SCCSID @(#)util.c 4.33.1.6 02/18/05 */
#include "vcxi.h"
#include "vp.h"
#include "memmap.h"
#include "buffer.h"
#include "debug.h"
#include "low.h"
#include "timedef.h"
#include "util.h"
#include "tdm.h"
#include "echo.h"
#include "ir.h"
#include "micro.h"
#include "kara.h"
#include "const.h"
#include "filesys.h"
#include "play.h"
#include "mpgaudio.h"
#ifdef MP3
#include "mp3.h"
#endif
#ifdef SCR_SAVER
#include "display.h"
#include "scrsaver.h"
#endif
#ifdef TWO_FIELDS_OSD
#include "cg.h"
#else
#include "fsosd.h"
#endif
/*
* Remote control depends on timer to get signal width. For convenience,
* we need the least significant 20 bits of starting timer value to be
* all 0's. Therefore, TIMER2_INTERVAL and multiplication factors are both
* set to 1024 instead of 1000.
*/
/*
* Real-time clock is always at DRAM location 0x20. The format is: 00hhmmss
* where hh is hour (0-23), mm is minute (0-59), ss is half second (0-119)
*
* Since this variable is always changing, I'll make sure the cache copy
* is consistent with the DRAM version even though we only use the DRAM
* version (otherwise, old cache data may destroy DRAM data by accident)
*/
unsigned int *RISC_ptr_realtime = (unsigned int *) 0x12000020;
unsigned int *RISC_cache_realtime = (unsigned int *) 0x20;
RESUME_INFO *VCD_ptr_resume_info = (RESUME_INFO *) 0x18; /* Byte location */
KEYDEBUGVAR(watchdog, 0);
/*
* WMA code was decompressed in WMA_CODE_start, r22-25 saved this address.
* If longjmp, these registers will be set to value in err_buf. So we
* should save the value in these registers into err_buf first, then we
* can do normal longjmp. Otherwise after longjmp, if run WMA code, system
* will crash. Also for JPEG.
*/
#if 0 /* we have updated err_buf in Decompress() */
volatile unsigned int regsave;
void my_longjmp(jmp_buf err_buf)
{
asm("st _regsave[r25],r22");
asm("nop");
err_buf[22-3] = (char *)regsave;
asm("st _regsave[r25],r23");
asm("nop");
err_buf[23-3] = (char *)regsave;
asm("st _regsave[r25],r24");
asm("nop");
err_buf[24-3] = (char *)regsave;
asm("st _regsave[r25],r25");
asm("nop");
err_buf[25-3] = (char *)regsave;
longjmp(err_buf,1);
}
#endif
/************************************************************************
Timer2 interrupt service.
************************************************************************/
void RISC_timer2_interrupt_service(void)
{
static uchar prev_osd_sec;
register unsigned int tmp = *RISC_ptr_realtime;
mvd[riface_clear_timer2] = 0; /* clear timer irq */
/* Timer reloaded automatically */
timer2_cnt++; /* based on 0.5secs period..will overflow in ~68yrs! */
#ifdef DSC
DSC_toggle(); /* Tell 3207 that we are not dead! */
#endif
#if (defined DSC || defined IO3898)
if (IS_POWER_DOWN) {
/*
* In the powerdown mode, there is no screen interrupt. I have
* to use timer interrupt to keep glbTimer moving. Otherwise,
* many waiting loop may hang due to glbTimer not moving.
*/
glbTimer += (60 * TIMER2_INTERVAL / 1000);
}
#endif
tmp++;
if ((tmp & 0xff) >= 120) {
/* Increment minute after 60 seconds */
tmp &= 0xffffff00;
tmp += 0x100;
if ((tmp & 0xff00) >= 0x3c00) {
/* Increment hour after 60 minutes */
tmp &= 0xffff0000;
tmp += 0x10000;
if (tmp >= 0x180000)
tmp = 0;
}
}
*RISC_cache_realtime = *RISC_ptr_realtime = tmp;
#ifdef TWO_FIELDS_OSD
CG_service(0); /* new OSD */
#endif
#ifdef PLAY20
/* keep time moving if we don't receive servo info,i.e. emergency */
if ((tmp&1) && (OSD_next_update<glbTimer)) { /* 1 second interval */
OSD_update_time = (prev_osd_sec != OSD_time_second);
prev_osd_sec = OSD_time_second;
}
if (REMOTE_VALID) {
/* We will do a longjump if the input key is POWER
key and the current_task is not 0. The user can
use the POWER key to power off machine if we
are looping in decoding task. */
if ((current_task != 0) && micro_is_power_key(codeIR)) {
longjmp(err_buf, 1);
}
}
#endif /* PLAY20 */
#if defined(WATCHDOG)
{
extern int xfer_mode;
if (!vcx_pause && (xfer_mode == 5)) {
/*
* We consider that system is dead if there are no
* xport or huffman xfer for both audio and video
* since last timer interrupt.
*/
int system_dead = !(VBV_ABV_xport_xfer_count &&
(VBV_ABV_huffman_xfer_count || TDM_isCDDA)) &&
!what_to_do_count ;
#ifdef WMA_CERT
system_dead = 0;
#endif
if (current_task && system_dead) {
#ifdef ECHO
/*
* When ECHO is on, the original system dead condition
* no longer holds. When the current_task is 6 (i.e. echo)
* we may not have any TDM/HUFF data.
*
* In every timer interrupt, we'll take note of the
* current ECHO_cnt. If between two timer interrupts,
* the ECHO_cnt stays the same, and the current task
* is ECHO, then we are really stucked in ECHO task.
*/
if ((current_task != 6) || (ECHO_cnt == ECHO_last_cnt))
#endif /* ECHO */
{
#ifdef MP3
if ( (STREAM_type != MP3_ID) ||
(current_task != 1) || (MPG_last_cnt == MPG_cnt) )
#endif /* MP3 */
{
KEYDEBUGINC(1, watchdog);
longjmp(err_buf, 1);
}
}
}
VBV_ABV_xport_xfer_count = VBV_ABV_huffman_xfer_count
= what_to_do_count = 0;
#ifdef MP3
if (STREAM_type == MP3_ID) MPG_last_cnt = MPG_cnt;
#endif
#ifdef ECHO
ECHO_last_cnt = ECHO_cnt;
#endif /* ECHO */
}
}
#endif
}
/**************************************************************************
buscon_irq_enable/disable is now a subroutine
**************************************************************************/
#ifndef BUSCON_IRQ_USE_MACRO
void buscon_irq_enable(int ch_runbit)
{
do {} while (!(mvd[buscon_dma_status] & ch_runbit));
mvd[riface_irqsuppress] = 0; asm("nop"); asm("nop");
gbl_buscon_irqmasks |= ch_runbit;
mvd[buscon_dma_irqmasks] = gbl_buscon_irqmasks;
}
void buscon_irq_disable(int ch_runbit)
{
mvd[riface_irqsuppress] = 0; asm("nop"); asm("nop");
gbl_buscon_irqmasks &= ~ch_runbit;
mvd[buscon_dma_irqmasks] = gbl_buscon_irqmasks;
}
#endif
/**************************************************************************
Start timer2.
**************************************************************************/
void RISC_start_timer2(void)
{
#if (defined DSC || defined IO3898)
if (IS_POWER_DOWN) timer2_period = 0x0 - (TIMER2_INTERVAL * IDLECLK * 100);
else timer2_period = 0x0 - (TIMER2_INTERVAL * CPUCLK * 100);
#else
timer2_period = 0x0 - (TIMER2_INTERVAL * CPUCLK * 100);
#endif /* DSC */
mvd[riface_clear_timer2] = 0; /* clear timer irq */
mvd[riface_timer2] = timer2_period;
*RISC_ptr_realtime = 0;
/* Mask off junk */
*RISC_cache_realtime = (*RISC_ptr_realtime &= x00ffffff);
enable_int(tim2);
}
/**************************************************************************
Write to the risc gateway fifo.
**************************************************************************/
void risc_fifo_write(int *p, int n)
{
while (n-- > 0) {
put_riscfifo(*p);
p++;
}
gbl_gate_control |= flush_r2b;
mvd[gate_control] = gbl_gate_control; /* Flush r2b gateway fifo */
}
#ifdef WMA_DEC
void RISC_flush_all()
{
int i;
volatile int k;
for (i = 0; i<16*1024; i+=16)
k = *((int *)i);
}
#endif
#if NOT_USED
/**************************************************************************
Read the risc gateway fifo.
**************************************************************************/
void risc_fifo_read(int *p, int n)
{
while (n-- > 0) {
get_riscfifo(*p);
p++;
}
}
/**************************************************************************
Flush the cache. This thing works, but rather slow. Better off using
RISC_to_dram().
**************************************************************************/
void RISC_flush(int start, int n)
{
int i, j;
volatile int k;
int first, last;
first = (start << 2) & 0xffff;
last = ((start + n) << 2) & 0xffff;
for (i = 0; i< 8192*2; i += 2048*2) {
for (j = first + i; j < last + i; j += 16) {
k = *((int *)j);
}
}
}
/****************************************************************************
*
2D DRAM to DRAM copy via the VP. dx must not exceed 256.
dx*dy must not exceed 128. You must have already set width3
(or width4 actually).
****************************************************************************
*/
#ifndef TWO_FIELDS_OSD
void dram_copy_2D_small(int dst, int src, int dx, int dy)
{
VP_xfer(NCMDQ_VP_xfer, VPCMD_W_DP, 0, VPDMA_WIDTH3, src, dx, dy);
VP_xfer(NCMDQ_VP_xfer, VPCMD_R_DP, 0, VPDMA_WIDTH3, dst, dx, dy);
}
#endif
#endif /* NOT_USED */
/*****************************************************************************
Move a block of memory from sram to dram.
*****************************************************************************/
void sram_to_dram(dst, srcp, n)
int dst; /* dword addr in DRAM */
int *srcp; /* source ptr in SRAM */
int n; /* block size in dwords */
{
int i, *dstp = (int *)dram(dst);
while (n--) {
*dstp++ = *srcp++;
for (i = 0; i < 32; i++)
asm("nop");
}
}
/*****************************************************************************
Move a block of memory from sram(actually it can be dram too) to dram.
This one is quicker if you have a large block.
*****************************************************************************/
void RISC_to_dram(dst, srcp, n)
int dst; /* dword addr in DRAM */
int *srcp; /* source ptr in SRAM */
int n; /* block size in dwords */
{
int dx, dy, m;
#if 1
buscon_wait(r2b);
#else
buscon_wait_timeout(r2b, 300000);
#endif
dy = n>>8; m = dy<<8; dx = n - m;
if (dy) {
buscon_xfer(r2b, BDMA_USEDX, dst, 256, dy);
dst += m;
risc_fifo_write(srcp, m);
srcp += m;
#if 1
buscon_wait(r2b);
#else
buscon_wait_timeout(r2b, 300000);
#endif
}
if (dx) {
buscon_xfer(r2b, 0, dst, dx, 1);
risc_fifo_write(srcp, dx);
#if 1
buscon_wait(r2b);
#else
buscon_wait_timeout(r2b, 300000);
#endif
}
}
/*****************************************************************************
DRAM clear via the VP.
*****************************************************************************/
void dram_clear(int dst, int n)
{
VP_ucode(NCMDQ_VP_ucode, clearalldp);
VP_ucode_wait();
while (n>0) {
int m = (n>128) ? 128 : n;
VP_xfer(NCMDQ_VP_xfer, VPCMD_R_DP, 0, 0, dst, m, 1);
dst += m;
n -= m;
}
VP_xfer_wait();
}
/*------------------------------------------------------------------------
Description:
This function is called on every video vertical sync and to increase
the glbTimer variable. If the output mode is PAL, we will add two
to the glbTimer. Thus, we only have one the glbTimer which is 1/60
second if the output mode is NTSC, or roughly 1/60 if the output
mode is PAL.
------------------------------------------------------------------------*/
void update_glbTimer()
{
static five_field_count;
glbTimer++;
five_field_count++;
if ((vcx_scn_height == 288) && (five_field_count >= 5)) {
/* adjust the PAL field time to NTSC field time */
glbTimer++;
five_field_count = 0;
}
}
/*
* Use this routine to flush the cache. Good to run at beginning in
* case we have done decompression before.
*
* We assume it is 4-way set associated with a line size of 16B.
*
* Input:
* addr: flush starting address
* size: cache size (8192B or 16384B)
*/
void UTIL_flushcache(addr, size)
unsigned int size;
register unsigned int addr;
{
unsigned int tmp1, tmp2, tmp3;
int i;
unsigned int setsz;
setsz = size / 4;
for (i = 0; i < setsz/16; i++) {
tmp1 = addr + setsz;
tmp2 = tmp1 + setsz;
tmp3 = tmp2 + setsz;
reg0 = *(unsigned int*)addr;
reg0 = *(unsigned int*)tmp1;
reg0 = *(unsigned int*)tmp2;
reg0 = *(unsigned int*)tmp3;
addr += 16;
}
}
#ifdef SPATIAL
/*
* Loader filter coefficients according to user specified spatializer level.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -