mirror of
https://github.com/RaySollium99/libpicofe.git
synced 2025-09-04 22:47:44 -04:00
remove PicoDrive-specific stuff, add readme
This commit is contained in:
parent
ca69c3e5a0
commit
f506842df2
73 changed files with 13 additions and 16178 deletions
529
gp2x/940ctl.c
529
gp2x/940ctl.c
|
@ -1,529 +0,0 @@
|
|||
// Code for communication with ARM940 and control of it.
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "code940/940shared.h"
|
||||
#include "soc_mmsp2.h"
|
||||
#include "soc.h"
|
||||
#include "../common/mp3.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/input.h"
|
||||
#include "../../pico/pico_int.h"
|
||||
#include "../../pico/sound/ym2612.h"
|
||||
#include "../../pico/sound/mix.h"
|
||||
|
||||
static unsigned char *shared_mem = 0;
|
||||
static _940_data_t *shared_data = 0;
|
||||
_940_ctl_t *shared_ctl = 0;
|
||||
unsigned char *mp3_mem = 0;
|
||||
|
||||
#define MP3_SIZE_MAX (0x400000 + 0x800000) // 12M
|
||||
#define CODE940_FILE "pico940_v3.bin"
|
||||
|
||||
int crashed_940 = 0;
|
||||
|
||||
static FILE *loaded_mp3 = 0;
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
#define MAXOUT (+32767)
|
||||
#define MINOUT (-32768)
|
||||
|
||||
/* limitter */
|
||||
#define Limit(val, max,min) { \
|
||||
if ( val > max ) val = max; \
|
||||
else if ( val < min ) val = min; \
|
||||
}
|
||||
|
||||
/* these will be managed locally on our side */
|
||||
static UINT8 ST_address; /* address register */
|
||||
static INT32 addr_A1; /* address line A1 */
|
||||
|
||||
static int writebuff_ptr = 0;
|
||||
|
||||
|
||||
/* YM2612 write */
|
||||
/* a = address */
|
||||
/* v = value */
|
||||
/* returns 1 if sample affecting state changed */
|
||||
int YM2612Write_940(unsigned int a, unsigned int v, int scanline)
|
||||
{
|
||||
int upd = 1; /* the write affects sample generation */
|
||||
|
||||
a &= 3;
|
||||
|
||||
//printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0: /* address port 0 */
|
||||
if (addr_A1 == 0 && ST_address == v)
|
||||
return 0; /* address already selected, don't send this command to 940 */
|
||||
ST_address = v;
|
||||
addr_A1 = 0;
|
||||
/* don't send DAC or timer related address changes to 940 */
|
||||
if (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a)
|
||||
return 0;
|
||||
upd = 0;
|
||||
break;
|
||||
|
||||
case 2: /* address port 1 */
|
||||
if (addr_A1 == 1 && ST_address == v)
|
||||
return 0;
|
||||
ST_address = v;
|
||||
addr_A1 = 1;
|
||||
upd = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("ym pass\n");
|
||||
|
||||
if (currentConfig.EmuOpt & 4)
|
||||
{
|
||||
UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;
|
||||
|
||||
/* detect rapid ym updates */
|
||||
if (upd && !(writebuff_ptr & 0x80000000) && scanline < 224)
|
||||
{
|
||||
int mid = Pico.m.pal ? 68 : 93;
|
||||
if (scanline > mid) {
|
||||
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, scanline);
|
||||
writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;
|
||||
writebuff_ptr |= 0x80000000;
|
||||
//printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, scanline, addr, v, upd);
|
||||
}
|
||||
}
|
||||
|
||||
/* queue this write for 940 */
|
||||
if ((writebuff_ptr&0xffff) < 2047) {
|
||||
writebuff[writebuff_ptr++ & 0xffff] = (a<<8)|v;
|
||||
} else {
|
||||
printf("warning: writebuff_ptr > 2047 ([%i] %02x)\n", a, v);
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // cause the engine to do updates once per frame only
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_BUSY(job) \
|
||||
(gp2x_memregs[0x3b46>>1] & (1<<(job-1)))
|
||||
|
||||
static void wait_busy_940(int job)
|
||||
{
|
||||
int i;
|
||||
|
||||
job--;
|
||||
for (i = 0; (gp2x_memregs[0x3b46>>1] & (1<<job)) && i < 0x10000; i++)
|
||||
spend_cycles(8*1024); // tested to be best for mp3 dec
|
||||
if (i < 0x10000) return;
|
||||
|
||||
/* 940 crashed */
|
||||
printf("940 crashed (cnt: %i, ve: ", shared_ctl->loopc);
|
||||
for (i = 0; i < 8; i++)
|
||||
printf("%i ", shared_ctl->vstarts[i]);
|
||||
printf(")\n");
|
||||
printf("irq pending flags: DUALCPU %04x, SRCPND %08lx (see 26), INTPND %08lx\n",
|
||||
gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);
|
||||
printf("last lr: %08x, lastjob: %i\n", shared_ctl->last_lr, shared_ctl->lastjob);
|
||||
printf("trying to interrupt..\n");
|
||||
gp2x_memregs[0x3B3E>>1] = 0xffff;
|
||||
for (i = 0; gp2x_memregs[0x3b46>>1] && i < 0x10000; i++)
|
||||
spend_cycles(8*1024);
|
||||
printf("i = 0x%x\n", i);
|
||||
printf("irq pending flags: DUALCPU %04x, SRCPND %08lx (see 26), INTPND %08lx\n",
|
||||
gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);
|
||||
printf("last lr: %08x, lastjob: %i\n", shared_ctl->last_lr, shared_ctl->lastjob);
|
||||
|
||||
me_update_msg("940 crashed, too much overclock?");
|
||||
engineState = PGS_Menu;
|
||||
crashed_940 = 1;
|
||||
}
|
||||
|
||||
|
||||
static void add_job_940(int job)
|
||||
{
|
||||
if (job <= 0 || job > 16) {
|
||||
printf("add_job_940: bad job: %i\n", job);
|
||||
return;
|
||||
}
|
||||
|
||||
// generate interrupt for this job
|
||||
job--;
|
||||
gp2x_memregs[(0x3B20+job*2)>>1] = 1;
|
||||
|
||||
// printf("added %i, pending %04x\n", job+1, gp2x_memregs[0x3b46>>1]);
|
||||
}
|
||||
|
||||
|
||||
void YM2612PicoStateLoad_940(void)
|
||||
{
|
||||
UINT8 *REGS = YM2612GetRegs();
|
||||
|
||||
/* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */
|
||||
add_job_940(JOB940_PICOSTATELOAD);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD)) wait_busy_940(JOB940_PICOSTATELOAD);
|
||||
|
||||
writebuff_ptr = 0;
|
||||
addr_A1 = *(INT32 *) (REGS + 0x200);
|
||||
}
|
||||
|
||||
void YM2612PicoStateSave2_940(int tat, int tbt)
|
||||
{
|
||||
UINT8 *ym_remote_regs, *ym_local_regs;
|
||||
add_job_940(JOB940_PICOSTATESAVE2);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATESAVE2)) wait_busy_940(JOB940_PICOSTATESAVE2);
|
||||
|
||||
ym_remote_regs = (UINT8 *) shared_ctl->writebuff0;
|
||||
ym_local_regs = YM2612GetRegs();
|
||||
if (*(UINT32 *)(ym_remote_regs + 0x100) != 0x41534d59) {
|
||||
printf("code940 didn't return valid save data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy addin data only */
|
||||
memcpy(ym_local_regs, ym_remote_regs, 0x20);
|
||||
memcpy(ym_local_regs + 0x100, ym_remote_regs + 0x100, 0x30);
|
||||
memcpy(ym_local_regs + 0x0b8, ym_remote_regs + 0x0b8, 0x48);
|
||||
memcpy(ym_local_regs + 0x1b8, ym_remote_regs + 0x1b8, 0x48);
|
||||
*(INT32 *)(ym_local_regs + 0x108) = tat;
|
||||
*(INT32 *)(ym_local_regs + 0x10c) = tbt;
|
||||
}
|
||||
|
||||
int YM2612PicoStateLoad2_940(int *tat, int *tbt)
|
||||
{
|
||||
UINT8 *ym_remote_regs, *ym_local_regs;
|
||||
ym_local_regs = YM2612GetRegs();
|
||||
ym_remote_regs = (UINT8 *) shared_ctl->writebuff0;
|
||||
|
||||
if (*(UINT32 *)(ym_local_regs + 0x100) != 0x41534d59)
|
||||
return -1;
|
||||
|
||||
*tat = *(INT32 *)(ym_local_regs + 0x108);
|
||||
*tbt = *(INT32 *)(ym_local_regs + 0x10c);
|
||||
|
||||
if (CHECK_BUSY(JOB940_YM2612UPDATEONE)) wait_busy_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
/* flush writes */
|
||||
if (shared_ctl->writebuffsel == 1) {
|
||||
shared_ctl->writebuff0[writebuff_ptr & 0xffff] = 0xffff;
|
||||
} else {
|
||||
shared_ctl->writebuff1[writebuff_ptr & 0xffff] = 0xffff;
|
||||
}
|
||||
shared_ctl->writebuffsel ^= 1;
|
||||
writebuff_ptr = 0;
|
||||
add_job_940(JOB940_PICOSTATELOAD2_PREP);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD2_PREP)) wait_busy_940(JOB940_PICOSTATELOAD2_PREP);
|
||||
|
||||
memcpy(ym_remote_regs, ym_local_regs, 0x200);
|
||||
|
||||
add_job_940(JOB940_PICOSTATELOAD2);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD2)) wait_busy_940(JOB940_PICOSTATELOAD2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void internal_reset(void)
|
||||
{
|
||||
writebuff_ptr = 0;
|
||||
ST_address = addr_A1 = -1;
|
||||
}
|
||||
|
||||
|
||||
/* this must be called after mmu hack, the allocated regions must not get cached */
|
||||
void sharedmem940_init(void)
|
||||
{
|
||||
if (shared_mem != NULL) return;
|
||||
|
||||
shared_mem = (unsigned char *) mmap(0, 0x210000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2000000);
|
||||
if (shared_mem == MAP_FAILED)
|
||||
{
|
||||
printf("mmap(shared_data) failed with %i\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
shared_data = (_940_data_t *) (shared_mem+0x100000);
|
||||
/* this area must not get buffered on either side */
|
||||
shared_ctl = (_940_ctl_t *) (shared_mem+0x200000);
|
||||
mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2400000);
|
||||
if (mp3_mem == MAP_FAILED)
|
||||
{
|
||||
printf("mmap(mp3_mem) failed with %i\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
crashed_940 = 1;
|
||||
}
|
||||
|
||||
|
||||
void sharedmem940_finish(void)
|
||||
{
|
||||
munmap(shared_mem, 0x210000);
|
||||
munmap(mp3_mem, MP3_SIZE_MAX);
|
||||
shared_mem = mp3_mem = NULL;
|
||||
shared_data = NULL;
|
||||
shared_ctl = NULL;
|
||||
}
|
||||
|
||||
|
||||
void YM2612Init_940(int baseclock, int rate)
|
||||
{
|
||||
printf("YM2612Init_940()\n");
|
||||
printf("Mem usage: shared_data: %i, shared_ctl: %i\n", sizeof(*shared_data), sizeof(*shared_ctl));
|
||||
|
||||
reset940(1, 2);
|
||||
pause940(1);
|
||||
|
||||
gp2x_memregs[0x3B40>>1] = 0; // disable DUALCPU interrupts for 920
|
||||
gp2x_memregs[0x3B42>>1] = 1; // enable DUALCPU interrupts for 940
|
||||
|
||||
gp2x_memregl[0x4504>>2] = 0; // make sure no FIQs will be generated
|
||||
gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller
|
||||
|
||||
|
||||
if (crashed_940)
|
||||
{
|
||||
unsigned char ucData[1024];
|
||||
int nRead, nLen = 0;
|
||||
char binpath[512];
|
||||
FILE *fp;
|
||||
|
||||
emu_make_path(binpath, CODE940_FILE, sizeof(binpath));
|
||||
fp = fopen(binpath, "rb");
|
||||
if(!fp)
|
||||
{
|
||||
memset(g_screen_ptr, 0, 320*240*2);
|
||||
text_out16(10, 100, "failed to open required file:");
|
||||
text_out16(10, 110, CODE940_FILE);
|
||||
gp2x_video_flip2();
|
||||
in_menu_wait(PBTN_MOK|PBTN_MBACK, 100);
|
||||
printf("failed to open %s\n", binpath);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
nRead = fread(ucData, 1, 1024, fp);
|
||||
if(nRead <= 0)
|
||||
break;
|
||||
memcpy(shared_mem + nLen, ucData, nRead);
|
||||
nLen += nRead;
|
||||
}
|
||||
fclose(fp);
|
||||
crashed_940 = 0;
|
||||
}
|
||||
|
||||
memset(shared_data, 0, sizeof(*shared_data));
|
||||
memset(shared_ctl, 0, sizeof(*shared_ctl));
|
||||
|
||||
/* cause local ym2612 to init REGS */
|
||||
YM2612Init_(baseclock, rate);
|
||||
|
||||
internal_reset();
|
||||
|
||||
loaded_mp3 = 0;
|
||||
|
||||
gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940
|
||||
gp2x_memregl[0x4500>>2] = 0xffffffff; // clear pending IRQs in SRCPND
|
||||
gp2x_memregl[0x4510>>2] = 0xffffffff; // clear pending IRQs in INTPND
|
||||
|
||||
/* start the 940 */
|
||||
reset940(0, 2);
|
||||
pause940(0);
|
||||
|
||||
// YM2612ResetChip_940(); // will be done on JOB940_YM2612INIT
|
||||
|
||||
/* now cause 940 to init it's ym2612 stuff */
|
||||
shared_ctl->baseclock = baseclock;
|
||||
shared_ctl->rate = rate;
|
||||
add_job_940(JOB940_INITALL);
|
||||
}
|
||||
|
||||
|
||||
void YM2612ResetChip_940(void)
|
||||
{
|
||||
//printf("YM2612ResetChip_940()\n");
|
||||
if (shared_data == NULL) {
|
||||
printf("YM2612ResetChip_940: reset before init?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
YM2612ResetChip_();
|
||||
internal_reset();
|
||||
|
||||
add_job_940(JOB940_YM2612RESETCHIP);
|
||||
}
|
||||
|
||||
|
||||
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)
|
||||
{
|
||||
int *ym_buf = shared_data->ym_buffer;
|
||||
int ym_active_chs;
|
||||
|
||||
//printf("YM2612UpdateOne_940()\n");
|
||||
|
||||
if (CHECK_BUSY(JOB940_YM2612UPDATEONE)) wait_busy_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
ym_active_chs = shared_ctl->ym_active_chs;
|
||||
|
||||
// mix in ym buffer. is_buf_empty means nobody mixed there anything yet and it may contain trash
|
||||
if (is_buf_empty && ym_active_chs) memcpy32(buffer, ym_buf, length<<stereo);
|
||||
else memset32(buffer, 0, length<<stereo);
|
||||
|
||||
if (shared_ctl->writebuffsel == 1) {
|
||||
shared_ctl->writebuff0[writebuff_ptr & 0xffff] = 0xffff;
|
||||
} else {
|
||||
shared_ctl->writebuff1[writebuff_ptr & 0xffff] = 0xffff;
|
||||
}
|
||||
writebuff_ptr = 0;
|
||||
|
||||
/* predict sample counter for next frame */
|
||||
if (PsndLen_exc_add) {
|
||||
length = PsndLen;
|
||||
if (PsndLen_exc_cnt + PsndLen_exc_add >= 0x10000) length++;
|
||||
}
|
||||
|
||||
/* give 940 ym job */
|
||||
shared_ctl->writebuffsel ^= 1;
|
||||
shared_ctl->length = length;
|
||||
shared_ctl->stereo = stereo;
|
||||
|
||||
add_job_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
return ym_active_chs;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
static int mp3_samples_ready = 0, mp3_buffer_offs = 0;
|
||||
static int mp3_play_bufsel = 0, mp3_job_started = 0;
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
int length_mp3;
|
||||
|
||||
if (!(PicoOpt & POPT_EXT_FM)) {
|
||||
mp3_update_local(buffer, length, stereo);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if playback was started, track not ended
|
||||
if (loaded_mp3 == NULL || shared_ctl->mp3_offs >= shared_ctl->mp3_len)
|
||||
return;
|
||||
|
||||
length_mp3 = length;
|
||||
if (PsndRate == 22050) length_mp3 <<= 1; // mp3s are locked to 44100Hz stereo
|
||||
else if (PsndRate == 11025) length_mp3 <<= 2; // so make length 44100ish
|
||||
|
||||
/* do we have to wait? */
|
||||
if (mp3_job_started && mp3_samples_ready < length_mp3) {
|
||||
if (CHECK_BUSY(JOB940_MP3DECODE)) wait_busy_940(JOB940_MP3DECODE);
|
||||
mp3_job_started = 0;
|
||||
mp3_samples_ready += 1152;
|
||||
}
|
||||
|
||||
/* mix mp3 data, only stereo */
|
||||
if (mp3_samples_ready >= length_mp3)
|
||||
{
|
||||
int shr = 0;
|
||||
void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;
|
||||
if (PsndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }
|
||||
else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }
|
||||
|
||||
if (1152 - mp3_buffer_offs >= length_mp3) {
|
||||
mix_samples(buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length<<1);
|
||||
|
||||
mp3_buffer_offs += length_mp3;
|
||||
} else {
|
||||
// collect samples from both buffers..
|
||||
int left = 1152 - mp3_buffer_offs;
|
||||
if (mp3_play_bufsel == 0)
|
||||
{
|
||||
mix_samples(buffer, shared_data->mp3_buffer[0] + mp3_buffer_offs*2, length<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mp3_play_bufsel = 1;
|
||||
} else {
|
||||
mix_samples(buffer, shared_data->mp3_buffer[1] + mp3_buffer_offs*2, (left>>shr)<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mix_samples(buffer + ((left>>shr)<<1),
|
||||
shared_data->mp3_buffer[0], (mp3_buffer_offs>>shr)<<1);
|
||||
mp3_play_bufsel = 0;
|
||||
}
|
||||
}
|
||||
mp3_samples_ready -= length_mp3;
|
||||
}
|
||||
|
||||
// ask to decode more if we already can
|
||||
if (!mp3_job_started)
|
||||
{
|
||||
mp3_job_started = 1;
|
||||
shared_ctl->mp3_buffsel ^= 1;
|
||||
add_job_940(JOB940_MP3DECODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mp3_start_play(void *f_, int pos) // pos is 0-1023
|
||||
{
|
||||
int byte_offs = 0;
|
||||
FILE *f = f_;
|
||||
|
||||
if (!(PicoOpt & POPT_EN_MCD_CDDA) || f == NULL)
|
||||
return;
|
||||
|
||||
if (!(PicoOpt & POPT_EXT_FM)) {
|
||||
mp3_start_play_local(f, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (loaded_mp3 != f)
|
||||
{
|
||||
if (PicoMessage != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
if (ftell(f) > 2*1024*1024)
|
||||
PicoMessage("Loading MP3...");
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(mp3_mem, 1, MP3_SIZE_MAX, f);
|
||||
if (!feof(f)) printf("Warning: mp3 was too large, not all data loaded.\n");
|
||||
shared_ctl->mp3_len = ftell(f);
|
||||
loaded_mp3 = f;
|
||||
|
||||
if (PicoOpt & POPT_EXT_FM) {
|
||||
// as we are going to change 940's cacheable area, we must invalidate it's cache..
|
||||
if (CHECK_BUSY(JOB940_MP3DECODE)) wait_busy_940(JOB940_MP3DECODE);
|
||||
add_job_940(JOB940_INVALIDATE_DCACHE);
|
||||
}
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
// seek..
|
||||
if (pos) {
|
||||
byte_offs = (shared_ctl->mp3_len << 6) >> 10;
|
||||
byte_offs *= pos;
|
||||
byte_offs >>= 6;
|
||||
}
|
||||
printf(" mp3 pos1024: %i, byte_offs %i/%i\n", pos, byte_offs, shared_ctl->mp3_len);
|
||||
|
||||
shared_ctl->mp3_offs = byte_offs;
|
||||
|
||||
// reset buffer pointers and stuff..
|
||||
mp3_samples_ready = mp3_buffer_offs = mp3_play_bufsel = 0;
|
||||
mp3_job_started = 0;
|
||||
shared_ctl->mp3_buffsel = 1; // will change to 0 on first decode
|
||||
|
||||
add_job_940(JOB940_MP3RESET);
|
||||
if (CHECK_BUSY(JOB940_MP3RESET)) wait_busy_940(JOB940_MP3RESET);
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
void sharedmem940_init(void);
|
||||
void sharedmem940_finish(void);
|
||||
|
||||
void YM2612Init_940(int baseclock, int rate);
|
||||
void YM2612ResetChip_940(void);
|
||||
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);
|
||||
|
||||
int YM2612Write_940(unsigned int a, unsigned int v, int scanline);
|
||||
|
||||
int YM2612PicoTick_940(int n);
|
||||
void YM2612PicoStateLoad_940(void);
|
||||
void YM2612PicoStateSave2_940(int tat, int tbt);
|
||||
int YM2612PicoStateLoad2_940(int *tat, int *tbt);
|
128
gp2x/Makefile
128
gp2x/Makefile
|
@ -1,128 +0,0 @@
|
|||
CROSS ?= arm-linux-
|
||||
|
||||
# settings
|
||||
use_cyclone = 1
|
||||
#use_musashi = 1
|
||||
use_drz80 = 1
|
||||
use_sh2drc = 1
|
||||
#use_sh2mame = 1
|
||||
|
||||
asm_memory = 1
|
||||
asm_render = 1
|
||||
asm_ym2612 = 1
|
||||
asm_misc = 1
|
||||
asm_cdpico = 1
|
||||
asm_cdmemory = 1
|
||||
asm_32xdraw = 1
|
||||
#profile = 1
|
||||
#drc_debug = 3
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ifeq "$(debug_cyclone)" "1"
|
||||
use_cyclone = 1
|
||||
use_musashi = 1
|
||||
endif
|
||||
ifeq "$(use_musashi)" "1"
|
||||
# due to CPU stop flag acces
|
||||
asm_cdpico = 0
|
||||
asm_cdmemory = 0
|
||||
endif
|
||||
|
||||
ARCH = arm
|
||||
DEFINES += ARM __GP2X__ IN_GP2X IN_EVDEV # BENCHMARK
|
||||
CFLAGS += -Wall -Winline -I../.. -I.
|
||||
ifeq ($(DEBUG),)
|
||||
CFLAGS += -O3 -fomit-frame-pointer -fstrict-aliasing -ffast-math
|
||||
endif
|
||||
CFLAGS += -mcpu=arm920t -mtune=arm920t
|
||||
ASFLAGS = -mcpu=arm920t -mfloat-abi=soft
|
||||
LDFLAGS += -lm -lpng
|
||||
|
||||
CC = $(CROSS)gcc
|
||||
STRIP = $(CROSS)strip
|
||||
AS = $(CROSS)as
|
||||
LD = $(CROSS)ld
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
# frontend
|
||||
OBJS += plat.o warm.o pollux_set.o soc.o soc_mmsp2.o soc_pollux.o soc_dummy.o emu.o in_gp2x.o
|
||||
# 940 core control
|
||||
OBJS += 940ctl.o
|
||||
|
||||
# ARM stuff
|
||||
OBJS += pico/carthw/svp/compiler.o pico/carthw/svp/stub_arm.o
|
||||
OBJS += pico/sound/mix_arm.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/emu.o platform/common/menu_pico.o platform/common/fonts.o platform/common/config.o \
|
||||
platform/common/arm_utils.o platform/common/arm_linux.o platform/common/readpng.o \
|
||||
platform/common/mp3_helix.o platform/common/input.o platform/common/main.o platform/common/mp3.o \
|
||||
platform/linux/sndout_oss.o platform/linux/plat.o platform/linux/in_evdev.o
|
||||
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
# zlib
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o
|
||||
|
||||
vpath %.c = ../..
|
||||
vpath %.s = ../..
|
||||
vpath %.S = ../..
|
||||
|
||||
DIRS += platform/gp2x platform/linux zlib unzip
|
||||
|
||||
|
||||
all: mkdirs PicoDrive
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/common_arm.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||
|
||||
# partial linking helps profiled builds due to section merging
|
||||
PicoDrive.o : $(OBJS) ../common/helix/$(CROSS)helix-mp3.a
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
# still using static, dynamic linking slows Wiz 1-10%
|
||||
# also libm on F100 is not compatible
|
||||
PicoDrive : PicoDrive.o
|
||||
@echo ">>>" $@
|
||||
$(CC) -static -o $@ $(CFLAGS) $^ $(LDFLAGS) -Wl,-Map=$@.map
|
||||
ifeq ($(DEBUG),)
|
||||
$(STRIP) $@
|
||||
endif
|
||||
|
||||
up: PicoDrive
|
||||
@cp -v PicoDrive /mnt/gp2x/mnt/sd/emus/PicoDrive/
|
||||
|
||||
clean: tidy
|
||||
$(RM) PicoDrive
|
||||
tidy:
|
||||
$(RM) $(OBJS)
|
||||
|
||||
readme.txt: ../../tools/textfilter ../base_readme.txt
|
||||
../../tools/textfilter ../base_readme.txt $@ GP2X
|
||||
|
||||
# ----------- release -----------
|
||||
VER ?= $(shell head -n 1 version.h | sed 's/.*"\(.*\)\.\(.*\)".*/\1\2/g')
|
||||
CODE940 = code940/pico940_v3.bin
|
||||
|
||||
rel: PicoDrive PicoDrive.gpe $(CODE940) readme.txt ../game_def.cfg \
|
||||
PicoDrive.png PicoDrive_s.png PicoDrive_t.png \
|
||||
warm_2.4.25.o warm_2.4.26-open2x.o warm_2.6.24.ko \
|
||||
../../pico/carthw.cfg
|
||||
mkdir -p out/PicoDrive/skin/
|
||||
cp $^ out/PicoDrive/
|
||||
cp PicoDrive.ini out/
|
||||
cp skin/*.png out/PicoDrive/skin/
|
||||
cp skin/*.txt out/PicoDrive/skin/
|
||||
mkdir out/bin_to_cso_mp3
|
||||
cp ../../tools/bin_to_cso_mp3/* out/bin_to_cso_mp3/
|
||||
cd out && zip -9 -r ../../../PicoDrive_$(VER).zip *
|
||||
rm -rf out
|
||||
|
||||
$(CODE940):
|
||||
make -C code940/
|
||||
|
915
gp2x/emu.c
915
gp2x/emu.c
|
@ -1,915 +0,0 @@
|
|||
/*
|
||||
* (c) Copyright 2006-2010 notaz, All rights reserved.
|
||||
*
|
||||
* For performance reasons 3 renderers are exported for both MD and 32x modes:
|
||||
* - 16bpp line renderer
|
||||
* - 8bpp line renderer (slightly faster)
|
||||
* - 8bpp tile renderer
|
||||
* In 32x mode:
|
||||
* - 32x layer is overlayed on top of 16bpp one
|
||||
* - line internal one done on PicoDraw2FB, then mixed with 32x
|
||||
* - tile internal one done on PicoDraw2FB, then mixed with 32x
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "plat_gp2x.h"
|
||||
#include "soc.h"
|
||||
#include "soc_pollux.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../common/fonts.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/input.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
#include <pico/patch.h>
|
||||
#include <pico/sound/mix.h>
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
#ifdef BENCHMARK
|
||||
#define OSD_FPS_X 220
|
||||
#else
|
||||
#define OSD_FPS_X 260
|
||||
#endif
|
||||
|
||||
|
||||
extern int crashed_940;
|
||||
|
||||
static short __attribute__((aligned(4))) sndBuffer[2*(44100+100)/50];
|
||||
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
|
||||
unsigned char *PicoDraw2FB = PicoDraw2FB_;
|
||||
static int osd_fps_x, osd_y, doing_bg_frame;
|
||||
const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL };
|
||||
const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL };
|
||||
enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT };
|
||||
|
||||
static int (*emu_scan_begin)(unsigned int num) = NULL;
|
||||
static int (*emu_scan_end)(unsigned int num) = NULL;
|
||||
|
||||
extern void *gp2x_screens[4];
|
||||
|
||||
|
||||
void pemu_prep_defconfig(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
defaultConfig.CPUclock = default_cpu_clock;
|
||||
defaultConfig.renderer32x = RT_8BIT_FAST;
|
||||
defaultConfig.analog_deadzone = 50;
|
||||
|
||||
soc = soc_detect();
|
||||
if (soc == SOCID_MMSP2)
|
||||
defaultConfig.s_PicoOpt |= POPT_EXT_FM;
|
||||
else if (soc == SOCID_POLLUX) {
|
||||
defaultConfig.EmuOpt |= EOPT_WIZ_TEAR_FIX|EOPT_SHOW_RTC;
|
||||
defaultConfig.s_PicoOpt |= POPT_EN_MCD_GFX;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
if (gp2x_dev_id != GP2X_DEV_GP2X)
|
||||
PicoOpt &= ~POPT_EXT_FM;
|
||||
if (gp2x_dev_id != GP2X_DEV_WIZ)
|
||||
currentConfig.EmuOpt &= ~EOPT_WIZ_TEAR_FIX;
|
||||
|
||||
if (currentConfig.gamma < 10 || currentConfig.gamma > 300)
|
||||
currentConfig.gamma = 100;
|
||||
|
||||
if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 1024)
|
||||
currentConfig.CPUclock = default_cpu_clock;
|
||||
}
|
||||
|
||||
static int get_renderer(void)
|
||||
{
|
||||
if (PicoAHW & PAHW_32X)
|
||||
return currentConfig.renderer32x;
|
||||
else
|
||||
return currentConfig.renderer;
|
||||
}
|
||||
|
||||
static void change_renderer(int diff)
|
||||
{
|
||||
int *r;
|
||||
if (PicoAHW & PAHW_32X)
|
||||
r = ¤tConfig.renderer32x;
|
||||
else
|
||||
r = ¤tConfig.renderer;
|
||||
*r += diff;
|
||||
|
||||
// 8bpp fast is not there (yet?)
|
||||
if ((PicoAHW & PAHW_SMS) && *r == RT_8BIT_FAST)
|
||||
(*r)++;
|
||||
|
||||
if (*r >= RT_COUNT)
|
||||
*r = 0;
|
||||
else if (*r < 0)
|
||||
*r = RT_COUNT - 1;
|
||||
}
|
||||
|
||||
#define is_16bit_mode() \
|
||||
(get_renderer() == RT_16BIT || (PicoAHW & PAHW_32X))
|
||||
|
||||
static void (*osd_text)(int x, int y, const char *text);
|
||||
|
||||
static void osd_text8(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+3) >> 2;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~3;
|
||||
p = (int *) ((char *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = 0xe0e0e0e0;
|
||||
}
|
||||
emu_text_out8(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text16(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+1) >> 1;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~1;
|
||||
p = (int *) ((short *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = (*p >> 2) & 0x39e7;
|
||||
}
|
||||
emu_text_out16(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text8_rot(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text) * 8;
|
||||
char *p = (char *)g_screen_ptr + 240*(320-x) + y;
|
||||
|
||||
while (len--) {
|
||||
memset(p, 0xe0, 8);
|
||||
p -= 240;
|
||||
}
|
||||
|
||||
emu_text_out8_rot(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text16_rot(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text) * 8;
|
||||
short *p = (short *)g_screen_ptr + 240*(320-x) + y;
|
||||
|
||||
while (len--) {
|
||||
memset(p, 0, 8*2);
|
||||
p -= 240;
|
||||
}
|
||||
|
||||
emu_text_out16_rot(x, y, text);
|
||||
}
|
||||
|
||||
static void draw_cd_leds(void)
|
||||
{
|
||||
int led_reg, pitch, scr_offs, led_offs;
|
||||
led_reg = Pico_mcd->s68k_regs[0];
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
pitch = 240;
|
||||
led_offs = -pitch * 6;
|
||||
scr_offs = pitch * (320 - 4);
|
||||
} else {
|
||||
pitch = 320;
|
||||
led_offs = 4;
|
||||
scr_offs = pitch * 2 + 4;
|
||||
}
|
||||
|
||||
if (!is_16bit_mode()) {
|
||||
#define p(x) px[(x) >> 2]
|
||||
// 8-bit modes
|
||||
unsigned int *px = (unsigned int *)((char *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
} else {
|
||||
#define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]
|
||||
// 16-bit modes
|
||||
unsigned int *px = (unsigned int *)((short *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0x06000600 : 0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xc000c000 : 0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_pico_ptr(void)
|
||||
{
|
||||
unsigned short *p = (unsigned short *)g_screen_ptr;
|
||||
int x, y, pitch = 320;
|
||||
|
||||
// only if pen enabled and for 16bit modes
|
||||
if (pico_inp_mode == 0 || currentConfig.EmuOpt != RT_16BIT)
|
||||
return;
|
||||
|
||||
x = pico_pen_x + PICO_PEN_ADJUST_X;
|
||||
y = pico_pen_y + PICO_PEN_ADJUST_Y;
|
||||
if (!(Pico.video.reg[12]&1) && !(PicoOpt & POPT_DIS_32C_BORDER))
|
||||
x += 32;
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
pitch = 240;
|
||||
p += (319 - x) * pitch + y;
|
||||
} else
|
||||
p += x + y * pitch;
|
||||
|
||||
p[0] ^= 0xffff;
|
||||
p[pitch-1] ^= 0xffff;
|
||||
p[pitch] ^= 0xffff;
|
||||
p[pitch+1] ^= 0xffff;
|
||||
p[pitch*2] ^= 0xffff;
|
||||
}
|
||||
|
||||
/* rot thing for Wiz */
|
||||
static unsigned char __attribute__((aligned(4))) rot_buff[320*4*2];
|
||||
|
||||
static int EmuScanBegin16_rot(unsigned int num)
|
||||
{
|
||||
DrawLineDest = rot_buff + (num & 3) * 320 * 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd16_rot(unsigned int num)
|
||||
{
|
||||
if ((num & 3) != 3)
|
||||
return 0;
|
||||
rotated_blit16(g_screen_ptr, rot_buff, num + 1,
|
||||
!(Pico.video.reg[12] & 1) && !(PicoOpt & POPT_EN_SOFTSCALE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanBegin8_rot(unsigned int num)
|
||||
{
|
||||
DrawLineDest = rot_buff + (num & 3) * 320;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd8_rot(unsigned int num)
|
||||
{
|
||||
if ((num & 3) != 3)
|
||||
return 0;
|
||||
rotated_blit8(g_screen_ptr, rot_buff, num + 1,
|
||||
!(Pico.video.reg[12] & 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* line doublers */
|
||||
static unsigned int ld_counter;
|
||||
static int ld_left, ld_lines;
|
||||
|
||||
static int EmuScanBegin16_ld(unsigned int num)
|
||||
{
|
||||
if ((signed int)(ld_counter - num) > 100)
|
||||
ld_counter = 0;
|
||||
|
||||
if (emu_scan_begin)
|
||||
return emu_scan_begin(ld_counter);
|
||||
else
|
||||
DrawLineDest = (char *)g_screen_ptr + 320 * ld_counter * gp2x_current_bpp / 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd16_ld(unsigned int num)
|
||||
{
|
||||
void *oldline = DrawLineDest;
|
||||
|
||||
if (emu_scan_end)
|
||||
emu_scan_end(ld_counter);
|
||||
|
||||
ld_counter++;
|
||||
ld_left--;
|
||||
if (ld_left <= 0) {
|
||||
ld_left = ld_lines;
|
||||
|
||||
EmuScanBegin16_ld(num);
|
||||
memcpy32(DrawLineDest, oldline, 320 * gp2x_current_bpp / 8 / 4);
|
||||
if (emu_scan_end)
|
||||
emu_scan_end(ld_counter);
|
||||
|
||||
ld_counter++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int localPal[0x100];
|
||||
static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border);
|
||||
static int (*make_local_pal)(int fast_mode);
|
||||
|
||||
static int make_local_pal_md(int fast_mode)
|
||||
{
|
||||
int pallen = 0xc0;
|
||||
|
||||
bgr444_to_rgb32(localPal, Pico.cram);
|
||||
if (fast_mode)
|
||||
return 0x40;
|
||||
|
||||
if (Pico.video.reg[0xC] & 8) { // shadow/hilight mode
|
||||
bgr444_to_rgb32_sh(localPal, Pico.cram);
|
||||
localPal[0xc0] = 0x0000c000;
|
||||
localPal[0xd0] = 0x00c00000;
|
||||
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
|
||||
localPal[0xf0] = 0x00ffffff;
|
||||
pallen = 0x100;
|
||||
}
|
||||
else if (rendstatus & PDRAW_SONIC_MODE) { // mid-frame palette changes
|
||||
bgr444_to_rgb32(localPal+0x40, HighPal);
|
||||
bgr444_to_rgb32(localPal+0x80, HighPal+0x40);
|
||||
}
|
||||
else
|
||||
memcpy32(localPal+0x80, localPal, 0x40); // for spr prio mess
|
||||
|
||||
return pallen;
|
||||
}
|
||||
|
||||
static int make_local_pal_sms(int fast_mode)
|
||||
{
|
||||
unsigned short *spal = Pico.cram;
|
||||
unsigned int *dpal = (void *)localPal;
|
||||
unsigned int i, t;
|
||||
|
||||
for (i = 0x40; i > 0; i--) {
|
||||
t = *spal++;
|
||||
t = ((t & 0x0003) << 22) | ((t & 0x000c) << 12) | ((t & 0x0030) << 2);
|
||||
t |= t >> 2;
|
||||
t |= t >> 4;
|
||||
*dpal++ = t;
|
||||
}
|
||||
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
void pemu_finalize_frame(const char *fps, const char *notice)
|
||||
{
|
||||
int emu_opt = currentConfig.EmuOpt;
|
||||
int ret;
|
||||
|
||||
if (PicoAHW & PAHW_32X)
|
||||
; // nothing to do
|
||||
else if (get_renderer() == RT_8BIT_FAST)
|
||||
{
|
||||
// 8bit fast renderer
|
||||
if (Pico.m.dirtyPal) {
|
||||
Pico.m.dirtyPal = 0;
|
||||
ret = make_local_pal(1);
|
||||
// feed new palette to our device
|
||||
gp2x_video_setpalette(localPal, ret);
|
||||
}
|
||||
// a hack for VR
|
||||
if (PicoAHW & PAHW_SVP)
|
||||
memset32((int *)(PicoDraw2FB+328*8+328*223), 0xe0e0e0e0, 328);
|
||||
// do actual copy
|
||||
vidcpyM2(g_screen_ptr, PicoDraw2FB+328*8,
|
||||
!(Pico.video.reg[12] & 1), !(PicoOpt & POPT_DIS_32C_BORDER));
|
||||
}
|
||||
else if (get_renderer() == RT_8BIT_ACC)
|
||||
{
|
||||
// 8bit accurate renderer
|
||||
if (Pico.m.dirtyPal)
|
||||
{
|
||||
Pico.m.dirtyPal = 0;
|
||||
ret = make_local_pal(0);
|
||||
gp2x_video_setpalette(localPal, ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (notice)
|
||||
osd_text(4, osd_y, notice);
|
||||
if (emu_opt & EOPT_SHOW_FPS)
|
||||
osd_text(osd_fps_x, osd_y, fps);
|
||||
if ((PicoAHW & PAHW_MCD) && (emu_opt & EOPT_EN_CD_LEDS))
|
||||
draw_cd_leds();
|
||||
if (PicoAHW & PAHW_PICO)
|
||||
draw_pico_ptr();
|
||||
}
|
||||
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
int stride = g_screen_width;
|
||||
gp2x_video_flip();
|
||||
|
||||
if (is_16bit_mode())
|
||||
stride *= 2;
|
||||
PicoDrawSetOutBuf(g_screen_ptr, stride);
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
#ifdef __GP2X__
|
||||
unsigned int plat_get_ticks_ms(void)
|
||||
{
|
||||
return gp2x_get_ticks_ms();
|
||||
}
|
||||
|
||||
unsigned int plat_get_ticks_us(void)
|
||||
{
|
||||
return gp2x_get_ticks_us();
|
||||
}
|
||||
#endif
|
||||
|
||||
void plat_wait_till_us(unsigned int us_to)
|
||||
{
|
||||
unsigned int now;
|
||||
|
||||
spend_cycles(1024);
|
||||
now = plat_get_ticks_us();
|
||||
|
||||
while ((signed int)(us_to - now) > 512)
|
||||
{
|
||||
spend_cycles(1024);
|
||||
now = plat_get_ticks_us();
|
||||
}
|
||||
}
|
||||
|
||||
void plat_video_wait_vsync(void)
|
||||
{
|
||||
gp2x_video_wait_vsync();
|
||||
}
|
||||
|
||||
void plat_status_msg_clear(void)
|
||||
{
|
||||
int is_8bit = !is_16bit_mode();
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
/* ugh.. */
|
||||
int i, u, *p;
|
||||
if (is_8bit) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
p = (int *)gp2x_screens[i] + (240-8) / 4;
|
||||
for (u = 320; u > 0; u--, p += 240/4)
|
||||
p[0] = p[1] = 0xe0e0e0e0;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
p = (int *)gp2x_screens[i] + (240-8)*2 / 4;
|
||||
for (u = 320; u > 0; u--, p += 240*2/4)
|
||||
p[0] = p[1] = p[2] = p[3] = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_8bit)
|
||||
gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
|
||||
else
|
||||
gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_next(const char *msg)
|
||||
{
|
||||
plat_status_msg_clear();
|
||||
pemu_finalize_frame("", msg);
|
||||
plat_video_flip();
|
||||
emu_status_msg("");
|
||||
|
||||
/* assumption: msg_busy_next gets called only when
|
||||
* something slow is about to happen */
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_first(const char *msg)
|
||||
{
|
||||
gp2x_memcpy_all_buffers(g_screen_ptr, 0, 320*240*2);
|
||||
plat_status_msg_busy_next(msg);
|
||||
}
|
||||
|
||||
static void vid_reset_mode(void)
|
||||
{
|
||||
int gp2x_mode = 16;
|
||||
int renderer = get_renderer();
|
||||
|
||||
PicoOpt &= ~POPT_ALT_RENDERER;
|
||||
emu_scan_begin = NULL;
|
||||
emu_scan_end = NULL;
|
||||
|
||||
switch (renderer) {
|
||||
case RT_16BIT:
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 0);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
break;
|
||||
case RT_8BIT_ACC:
|
||||
PicoDrawSetOutFormat(PDF_8BIT, 0);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width);
|
||||
gp2x_mode = 8;
|
||||
break;
|
||||
case RT_8BIT_FAST:
|
||||
PicoOpt |= POPT_ALT_RENDERER;
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
vidcpyM2 = vidcpy_m2;
|
||||
gp2x_mode = 8;
|
||||
break;
|
||||
default:
|
||||
printf("bad renderer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (PicoAHW & PAHW_32X) {
|
||||
// Wiz 16bit is an exception, uses line rendering due to rotation mess
|
||||
if (renderer == RT_16BIT && (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)) {
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
PicoDraw32xSetFrameMode(0, 0);
|
||||
}
|
||||
else {
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
PicoDraw32xSetFrameMode(1, 0);
|
||||
}
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
gp2x_mode = 16;
|
||||
}
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
if ((PicoAHW & PAHW_32X) || renderer == RT_16BIT) {
|
||||
emu_scan_begin = EmuScanBegin16_rot;
|
||||
emu_scan_end = EmuScanEnd16_rot;
|
||||
}
|
||||
else if (renderer == RT_8BIT_ACC) {
|
||||
emu_scan_begin = EmuScanBegin8_rot;
|
||||
emu_scan_end = EmuScanEnd8_rot;
|
||||
}
|
||||
else if (renderer == RT_8BIT_FAST)
|
||||
vidcpyM2 = vidcpy_m2_rot;
|
||||
}
|
||||
|
||||
PicoDrawSetCallbacks(emu_scan_begin, emu_scan_end);
|
||||
|
||||
if (is_16bit_mode())
|
||||
osd_text = (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) ? osd_text16_rot : osd_text16;
|
||||
else
|
||||
osd_text = (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) ? osd_text8_rot : osd_text8;
|
||||
|
||||
gp2x_video_wait_vsync();
|
||||
if (!is_16bit_mode()) {
|
||||
// setup pal for 8-bit modes
|
||||
localPal[0xc0] = 0x0000c000; // MCD LEDs
|
||||
localPal[0xd0] = 0x00c00000;
|
||||
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
|
||||
localPal[0xf0] = 0x00ffffff;
|
||||
gp2x_video_setpalette(localPal, 0x100);
|
||||
gp2x_memset_all_buffers(0, 0xe0, 320*240);
|
||||
}
|
||||
else
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)
|
||||
gp2x_mode = -gp2x_mode;
|
||||
|
||||
gp2x_video_changemode(gp2x_mode);
|
||||
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
PicoOpt &= ~POPT_EN_SOFTSCALE;
|
||||
if (currentConfig.scaling == EOPT_SCALE_SW)
|
||||
PicoOpt |= POPT_EN_SOFTSCALE;
|
||||
|
||||
// palette converters for 8bit modes
|
||||
make_local_pal = (PicoAHW & PAHW_SMS) ? make_local_pal_sms : make_local_pal_md;
|
||||
}
|
||||
|
||||
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||
{
|
||||
int scalex = 320, scaley = 240;
|
||||
int ln_offs = 0;
|
||||
|
||||
if (doing_bg_frame)
|
||||
return;
|
||||
|
||||
osd_fps_x = OSD_FPS_X;
|
||||
osd_y = 232;
|
||||
|
||||
/* set up hwscaling here */
|
||||
PicoOpt &= ~POPT_DIS_32C_BORDER;
|
||||
if (is_32cols && currentConfig.scaling == EOPT_SCALE_HW) {
|
||||
scalex = 256;
|
||||
PicoOpt |= POPT_DIS_32C_BORDER;
|
||||
osd_fps_x = OSD_FPS_X - 64;
|
||||
}
|
||||
|
||||
if (currentConfig.vscaling == EOPT_SCALE_HW) {
|
||||
ln_offs = start_line;
|
||||
scaley = line_count;
|
||||
osd_y = start_line + line_count - 8;
|
||||
}
|
||||
|
||||
gp2x_video_RGB_setscaling(ln_offs, scalex, scaley);
|
||||
|
||||
/* line doubling */
|
||||
if (currentConfig.vscaling == EOPT_SCALE_SW && line_count < 240) {
|
||||
ld_lines = ld_left = line_count / (240 - line_count);
|
||||
PicoDrawSetCallbacks(EmuScanBegin16_ld, EmuScanEnd16_ld);
|
||||
}
|
||||
|
||||
// clear whole screen in all buffers
|
||||
if (!is_16bit_mode())
|
||||
gp2x_memset_all_buffers(0, 0xe0, 320*240);
|
||||
else
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
}
|
||||
|
||||
void plat_video_toggle_renderer(int change, int is_menu_call)
|
||||
{
|
||||
change_renderer(change);
|
||||
|
||||
if (is_menu_call)
|
||||
return;
|
||||
|
||||
vid_reset_mode();
|
||||
rendstatus_old = -1;
|
||||
|
||||
if (PicoAHW & PAHW_32X)
|
||||
emu_status_msg(renderer_names32x[get_renderer()]);
|
||||
else
|
||||
emu_status_msg(renderer_names[get_renderer()]);
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
static void RunEventsPico(unsigned int events)
|
||||
{
|
||||
int ret, px, py, lim_x;
|
||||
static int pdown_frames = 0;
|
||||
|
||||
// for F200
|
||||
ret = gp2x_touchpad_read(&px, &py);
|
||||
if (ret >= 0)
|
||||
{
|
||||
if (ret > 35000)
|
||||
{
|
||||
if (pdown_frames++ > 5)
|
||||
PicoPad[0] |= 0x20;
|
||||
|
||||
pico_pen_x = px;
|
||||
pico_pen_y = py;
|
||||
if (!(Pico.video.reg[12]&1)) {
|
||||
pico_pen_x -= 32;
|
||||
if (pico_pen_x < 0) pico_pen_x = 0;
|
||||
if (pico_pen_x > 248) pico_pen_x = 248;
|
||||
}
|
||||
if (pico_pen_y > 224) pico_pen_y = 224;
|
||||
}
|
||||
else
|
||||
pdown_frames = 0;
|
||||
|
||||
//if (ret == 0)
|
||||
// PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void plat_update_volume(int has_changed, int is_up)
|
||||
{
|
||||
static int prev_frame = 0, wait_frames = 0;
|
||||
int vol = currentConfig.volume;
|
||||
int need_low_volume = 0;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
if ((PicoOpt & POPT_EN_STEREO) && soc == SOCID_MMSP2)
|
||||
need_low_volume = 1;
|
||||
|
||||
if (has_changed)
|
||||
{
|
||||
if (need_low_volume && vol < 5 && prev_frame == Pico.m.frame_count - 1 && wait_frames < 12)
|
||||
wait_frames++;
|
||||
else {
|
||||
if (is_up) {
|
||||
if (vol < 99) vol++;
|
||||
} else {
|
||||
if (vol > 0) vol--;
|
||||
}
|
||||
wait_frames = 0;
|
||||
sndout_oss_setvol(vol, vol);
|
||||
currentConfig.volume = vol;
|
||||
}
|
||||
emu_status_msg("VOL: %02i", vol);
|
||||
prev_frame = Pico.m.frame_count;
|
||||
}
|
||||
|
||||
if (!need_low_volume)
|
||||
return;
|
||||
|
||||
/* set the right mixer func */
|
||||
if (vol >= 5)
|
||||
PsndMix_32_to_16l = mix_32_to_16l_stereo;
|
||||
else {
|
||||
mix_32_to_16l_level = 5 - vol;
|
||||
PsndMix_32_to_16l = mix_32_to_16l_stereo_lvl;
|
||||
}
|
||||
}
|
||||
|
||||
static void oss_write_nonblocking(int len)
|
||||
{
|
||||
// sndout_oss_can_write() is not reliable, only use with no_frmlimit
|
||||
if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len))
|
||||
return;
|
||||
|
||||
sndout_oss_write_nb(PsndOut, len);
|
||||
}
|
||||
|
||||
void pemu_sound_start(void)
|
||||
{
|
||||
static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;
|
||||
|
||||
PsndOut = NULL;
|
||||
|
||||
// prepare sound stuff
|
||||
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||
{
|
||||
int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;
|
||||
int snd_rate_oss = PsndRate;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
memset(sndBuffer, 0, sizeof(sndBuffer));
|
||||
PsndOut = sndBuffer;
|
||||
PicoWriteSound = oss_write_nonblocking;
|
||||
plat_update_volume(0, 0);
|
||||
|
||||
printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
|
||||
PsndRate, PsndLen, is_stereo, Pico.m.pal);
|
||||
sndout_oss_start(snd_rate_oss, is_stereo, 1);
|
||||
sndout_oss_setvol(currentConfig.volume, currentConfig.volume);
|
||||
|
||||
soc = soc_detect();
|
||||
if (soc == SOCID_POLLUX)
|
||||
PsndRate = pollux_get_real_snd_rate(PsndRate);
|
||||
|
||||
#define SOUND_RERATE_FLAGS (POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO|POPT_EXT_FM|POPT_EN_MCD_CDDA)
|
||||
if (PsndRate != PsndRate_old || Pico.m.pal != pal_old || ((PicoOpt & POPT_EXT_FM) && crashed_940) ||
|
||||
((PicoOpt ^ PicoOpt_old) & SOUND_RERATE_FLAGS)) {
|
||||
PsndRerate(Pico.m.frame_count ? 1 : 0);
|
||||
}
|
||||
|
||||
PsndRate_old = PsndRate;
|
||||
PicoOpt_old = PicoOpt;
|
||||
pal_old = Pico.m.pal;
|
||||
}
|
||||
}
|
||||
|
||||
static const int sound_rates[] = { 44100, 32000, 22050, 16000, 11025, 8000 };
|
||||
|
||||
void pemu_sound_stop(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* get back from Pollux pain */
|
||||
PsndRate += 1000;
|
||||
for (i = 0; i < ARRAY_SIZE(sound_rates); i++) {
|
||||
if (PsndRate >= sound_rates[i]) {
|
||||
PsndRate = sound_rates[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_sound_wait(void)
|
||||
{
|
||||
// don't need to do anything, writes will block by themselves
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
doing_bg_frame = 1;
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
PicoDraw32xSetFrameMode(0, 0);
|
||||
PicoDrawSetCallbacks(NULL, NULL);
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
emu_cmn_forced_frame(no_scale, do_emu);
|
||||
|
||||
g_menubg_src_ptr = g_screen_ptr;
|
||||
doing_bg_frame = 0;
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void tga_dump(void)
|
||||
{
|
||||
#define BYTE unsigned char
|
||||
#define WORD unsigned short
|
||||
struct
|
||||
{
|
||||
BYTE IDLength; /* 00h Size of Image ID field */
|
||||
BYTE ColorMapType; /* 01h Color map type */
|
||||
BYTE ImageType; /* 02h Image type code */
|
||||
WORD CMapStart; /* 03h Color map origin */
|
||||
WORD CMapLength; /* 05h Color map length */
|
||||
BYTE CMapDepth; /* 07h Depth of color map entries */
|
||||
WORD XOffset; /* 08h X origin of image */
|
||||
WORD YOffset; /* 0Ah Y origin of image */
|
||||
WORD Width; /* 0Ch Width of image */
|
||||
WORD Height; /* 0Eh Height of image */
|
||||
BYTE PixelDepth; /* 10h Image pixel size */
|
||||
BYTE ImageDescriptor; /* 11h Image descriptor byte */
|
||||
} __attribute__((packed)) TGAHEAD;
|
||||
static unsigned short oldscr[320*240];
|
||||
FILE *f; char name[128]; int i;
|
||||
|
||||
memset(&TGAHEAD, 0, sizeof(TGAHEAD));
|
||||
TGAHEAD.ImageType = 2;
|
||||
TGAHEAD.Width = 320;
|
||||
TGAHEAD.Height = 240;
|
||||
TGAHEAD.PixelDepth = 16;
|
||||
TGAHEAD.ImageDescriptor = 2<<4; // image starts at top-left
|
||||
|
||||
#define CONV(X) (((X>>1)&0x7fe0)|(X&0x1f)) // 555?
|
||||
|
||||
for (i = 0; i < 320*240; i++)
|
||||
if(oldscr[i] != CONV(((unsigned short *)g_screen_ptr)[i])) break;
|
||||
if (i < 320*240)
|
||||
{
|
||||
for (i = 0; i < 320*240; i++)
|
||||
oldscr[i] = CONV(((unsigned short *)g_screen_ptr)[i]);
|
||||
sprintf(name, "%05i.tga", Pico.m.frame_count);
|
||||
f = fopen(name, "wb");
|
||||
if (!f) { printf("!f\n"); exit(1); }
|
||||
fwrite(&TGAHEAD, 1, sizeof(TGAHEAD), f);
|
||||
fwrite(oldscr, 1, 320*240*2, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0;
|
||||
static int gp2x_old_gamma = 100;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
|
||||
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_RAM_TIMINGS) {
|
||||
if (currentConfig.EmuOpt & EOPT_RAM_TIMINGS)
|
||||
set_ram_timings();
|
||||
else
|
||||
unset_ram_timings();
|
||||
}
|
||||
|
||||
if (gp2x_old_clock < 0)
|
||||
gp2x_old_clock = default_cpu_clock;
|
||||
if (gp2x_old_clock != currentConfig.CPUclock && gp2x_set_cpuclk != NULL) {
|
||||
printf("changing clock to %i...", currentConfig.CPUclock); fflush(stdout);
|
||||
gp2x_set_cpuclk(currentConfig.CPUclock);
|
||||
gp2x_old_clock = currentConfig.CPUclock;
|
||||
printf(" done\n");
|
||||
}
|
||||
|
||||
if (gp2x_old_gamma != currentConfig.gamma || ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_A_SN_GAMMA)) {
|
||||
set_lcd_gamma(currentConfig.gamma, !!(currentConfig.EmuOpt & EOPT_A_SN_GAMMA));
|
||||
gp2x_old_gamma = currentConfig.gamma;
|
||||
printf("updated gamma to %i, A_SN's curve: %i\n", currentConfig.gamma, !!(currentConfig.EmuOpt&0x1000));
|
||||
}
|
||||
|
||||
if (((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_VSYNC) || Pico.m.pal != pal_old) {
|
||||
if ((currentConfig.EmuOpt & EOPT_VSYNC) || soc == SOCID_POLLUX)
|
||||
set_lcd_custom_rate(Pico.m.pal);
|
||||
else if (EmuOpt_old & EOPT_VSYNC)
|
||||
unset_lcd_custom_rate();
|
||||
}
|
||||
|
||||
if (gp2x_dev_id == GP2X_DEV_CAANOO)
|
||||
in_set_config_int(in_name_to_id("evdev:pollux-analog"), IN_CFG_ABS_DEAD_ZONE,
|
||||
currentConfig.analog_deadzone);
|
||||
|
||||
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_MMUHACK)
|
||||
gp2x_make_fb_bufferable(currentConfig.EmuOpt & EOPT_MMUHACK);
|
||||
|
||||
EmuOpt_old = currentConfig.EmuOpt;
|
||||
pal_old = Pico.m.pal;
|
||||
|
||||
// make sure we are in correct mode
|
||||
change_renderer(0);
|
||||
vid_reset_mode();
|
||||
|
||||
// dirty buffers better go now than during gameplay
|
||||
sync();
|
||||
sleep(0);
|
||||
|
||||
pemu_sound_start();
|
||||
}
|
||||
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
|
||||
/* do one more frame for menu bg */
|
||||
pemu_forced_frame(0, 1);
|
||||
}
|
||||
|
128
gp2x/menu.c
128
gp2x/menu.c
|
@ -1,128 +0,0 @@
|
|||
#include <time.h>
|
||||
#include "soc.h"
|
||||
#include "plat_gp2x.h"
|
||||
|
||||
static void menu_main_plat_draw(void)
|
||||
{
|
||||
static time_t last_bat_read = 0;
|
||||
static int last_bat_val = -1;
|
||||
unsigned short *bp = g_screen_ptr;
|
||||
int bat_h = me_mfont_h * 2 / 3;
|
||||
int i, u, w, wfill, batt_val;
|
||||
struct tm *tmp;
|
||||
time_t ltime;
|
||||
char time_s[16];
|
||||
|
||||
if (!(currentConfig.EmuOpt & EOPT_SHOW_RTC))
|
||||
return;
|
||||
|
||||
ltime = time(NULL);
|
||||
tmp = gmtime(<ime);
|
||||
strftime(time_s, sizeof(time_s), "%H:%M", tmp);
|
||||
|
||||
text_out16(g_screen_width - me_mfont_w * 6, me_mfont_h + 2, time_s);
|
||||
|
||||
if (ltime - last_bat_read > 10) {
|
||||
last_bat_read = ltime;
|
||||
last_bat_val = batt_val = gp2x_read_battery();
|
||||
}
|
||||
else
|
||||
batt_val = last_bat_val;
|
||||
|
||||
if (batt_val < 0 || batt_val > 100)
|
||||
return;
|
||||
|
||||
/* battery info */
|
||||
bp += (me_mfont_h * 2 + 2) * g_screen_width + g_screen_width - me_mfont_w * 3 - 3;
|
||||
for (i = 0; i < me_mfont_w * 2; i++)
|
||||
bp[i] = menu_text_color;
|
||||
for (i = 0; i < me_mfont_w * 2; i++)
|
||||
bp[i + g_screen_width * bat_h] = menu_text_color;
|
||||
for (i = 0; i <= bat_h; i++)
|
||||
bp[i * g_screen_width] =
|
||||
bp[i * g_screen_width + me_mfont_w * 2] = menu_text_color;
|
||||
for (i = 2; i < bat_h - 1; i++)
|
||||
bp[i * g_screen_width - 1] =
|
||||
bp[i * g_screen_width - 2] = menu_text_color;
|
||||
|
||||
w = me_mfont_w * 2 - 1;
|
||||
wfill = batt_val * w / 100;
|
||||
for (u = 1; u < bat_h; u++)
|
||||
for (i = 0; i < wfill; i++)
|
||||
bp[(w - i) + g_screen_width * u] = menu_text_color;
|
||||
}
|
||||
|
||||
// ------------ gfx options menu ------------
|
||||
|
||||
static const char *mgn_aopt_gamma(int id, int *offs)
|
||||
{
|
||||
sprintf(static_buff, "%i.%02i", currentConfig.gamma / 100, currentConfig.gamma % 100);
|
||||
return static_buff;
|
||||
}
|
||||
|
||||
|
||||
const char *men_scaling_opts[] = { "OFF", "software", "hardware", NULL };
|
||||
|
||||
#define MENU_OPTIONS_GFX \
|
||||
mee_enum ("Horizontal scaling", MA_OPT_SCALING, currentConfig.scaling, men_scaling_opts), \
|
||||
mee_enum ("Vertical scaling", MA_OPT_VSCALING, currentConfig.vscaling, men_scaling_opts), \
|
||||
mee_onoff ("Tearing Fix", MA_OPT_TEARING_FIX, currentConfig.EmuOpt, EOPT_WIZ_TEAR_FIX), \
|
||||
mee_range_cust("Gamma correction", MA_OPT2_GAMMA, currentConfig.gamma, 1, 300, mgn_aopt_gamma), \
|
||||
mee_onoff ("A_SN's gamma curve", MA_OPT2_A_SN_GAMMA, currentConfig.EmuOpt, EOPT_A_SN_GAMMA), \
|
||||
mee_onoff ("Vsync", MA_OPT2_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC),
|
||||
|
||||
#define MENU_OPTIONS_ADV \
|
||||
mee_onoff ("Use second CPU for sound", MA_OPT_ARM940_SOUND, PicoOpt, POPT_EXT_FM), \
|
||||
mee_onoff ("RAM overclock", MA_OPT2_RAMTIMINGS, currentConfig.EmuOpt, EOPT_RAM_TIMINGS), \
|
||||
mee_onoff ("MMU hack", MA_OPT2_SQUIDGEHACK, currentConfig.EmuOpt, EOPT_MMUHACK), \
|
||||
mee_onoff ("SVP dynarec", MA_OPT2_SVP_DYNAREC, PicoOpt, POPT_EN_SVP_DRC), \
|
||||
mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC),
|
||||
|
||||
|
||||
static menu_entry e_menu_adv_options[];
|
||||
static menu_entry e_menu_gfx_options[];
|
||||
static menu_entry e_menu_options[];
|
||||
static menu_entry e_menu_keyconfig[];
|
||||
|
||||
void gp2x_menu_init(void)
|
||||
{
|
||||
static menu_entry *cpu_clk_ent;
|
||||
int i;
|
||||
|
||||
i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
|
||||
cpu_clk_ent = &e_menu_options[i];
|
||||
|
||||
/* disable by default.. */
|
||||
me_enable(e_menu_adv_options, MA_OPT_ARM940_SOUND, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT_TEARING_FIX, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_GAMMA, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_A_SN_GAMMA, 0);
|
||||
|
||||
switch (gp2x_dev_id) {
|
||||
case GP2X_DEV_GP2X:
|
||||
me_enable(e_menu_adv_options, MA_OPT_ARM940_SOUND, 1);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_GAMMA, 1);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_A_SN_GAMMA, 1);
|
||||
cpu_clk_ent->name = "GP2X CPU clocks";
|
||||
break;
|
||||
case GP2X_DEV_WIZ:
|
||||
me_enable(e_menu_gfx_options, MA_OPT_TEARING_FIX, 1);
|
||||
cpu_clk_ent->name = "Wiz/Caanoo CPU clock";
|
||||
break;
|
||||
case GP2X_DEV_CAANOO:
|
||||
cpu_clk_ent->name = "Wiz/Caanoo CPU clock";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gp2x_set_cpuclk == NULL)
|
||||
cpu_clk_ent->name = "";
|
||||
|
||||
if (gp2x_dev_id != GP2X_DEV_GP2X)
|
||||
men_scaling_opts[2] = NULL; /* leave only off and sw */
|
||||
|
||||
if (gp2x_dev_id != GP2X_DEV_CAANOO)
|
||||
me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
|
||||
}
|
||||
|
233
gp2x/plat.c
233
gp2x/plat.c
|
@ -1,233 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "plat_gp2x.h"
|
||||
#include "soc.h"
|
||||
#include "warm.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/readpng.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/input.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
|
||||
#include <pico/pico.h>
|
||||
|
||||
/* GP2X local */
|
||||
int default_cpu_clock;
|
||||
int gp2x_dev_id;
|
||||
int gp2x_current_bpp;
|
||||
void *gp2x_screens[4];
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
static const char * const caanoo_keys[KEY_MAX + 1] = {
|
||||
[0 ... KEY_MAX] = NULL,
|
||||
[KEY_UP] = "Up",
|
||||
[KEY_LEFT] = "Left",
|
||||
[KEY_RIGHT] = "Right",
|
||||
[KEY_DOWN] = "Down",
|
||||
[BTN_TRIGGER] = "A",
|
||||
[BTN_THUMB] = "X",
|
||||
[BTN_THUMB2] = "B",
|
||||
[BTN_TOP] = "Y",
|
||||
[BTN_TOP2] = "L",
|
||||
[BTN_PINKIE] = "R",
|
||||
[BTN_BASE] = "Home",
|
||||
[BTN_BASE2] = "Lock",
|
||||
[BTN_BASE3] = "I",
|
||||
[BTN_BASE4] = "II",
|
||||
[BTN_BASE5] = "Push",
|
||||
};
|
||||
|
||||
struct in_default_bind in_evdev_defbinds[] =
|
||||
{
|
||||
/* MXYZ SACB RLDU */
|
||||
{ KEY_UP, IN_BINDTYPE_PLAYER12, 0 },
|
||||
{ KEY_DOWN, IN_BINDTYPE_PLAYER12, 1 },
|
||||
{ KEY_LEFT, IN_BINDTYPE_PLAYER12, 2 },
|
||||
{ KEY_RIGHT, IN_BINDTYPE_PLAYER12, 3 },
|
||||
{ KEY_S, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ KEY_D, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ KEY_A, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ KEY_ENTER, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ KEY_BACKSLASH, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
/* Caanoo */
|
||||
{ BTN_THUMB, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ BTN_THUMB2, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ BTN_TRIGGER, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ BTN_BASE3, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ BTN_TOP2, IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
|
||||
{ BTN_PINKIE, IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
|
||||
{ BTN_BASE, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
void gp2x_video_changemode(int bpp)
|
||||
{
|
||||
gp2x_video_changemode_ll(bpp);
|
||||
|
||||
gp2x_current_bpp = bpp < 0 ? -bpp : bpp;
|
||||
}
|
||||
|
||||
static void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)
|
||||
{
|
||||
char *dst;
|
||||
if (buffers & (1<<0)) { dst = (char *)gp2x_screens[0] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<1)) { dst = (char *)gp2x_screens[1] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<2)) { dst = (char *)gp2x_screens[2] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<3)) { dst = (char *)gp2x_screens[3] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
}
|
||||
|
||||
void gp2x_memcpy_all_buffers(void *data, int offset, int len)
|
||||
{
|
||||
gp2x_memcpy_buffers(0xf, data, offset, len);
|
||||
}
|
||||
|
||||
void gp2x_memset_all_buffers(int offset, int byte, int len)
|
||||
{
|
||||
memset((char *)gp2x_screens[0] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[1] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[2] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[3] + offset, byte, len);
|
||||
}
|
||||
|
||||
void gp2x_make_fb_bufferable(int yes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
yes = yes ? 1 : 0;
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[0], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[1], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[2], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[3], 320*240*2);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "could not make fb buferable.\n");
|
||||
else
|
||||
printf("made fb buferable.\n");
|
||||
}
|
||||
|
||||
/* common */
|
||||
void plat_video_menu_enter(int is_rom_loaded)
|
||||
{
|
||||
if (gp2x_current_bpp != 16 || gp2x_dev_id == GP2X_DEV_WIZ) {
|
||||
/* try to switch nicely avoiding glitches */
|
||||
gp2x_video_wait_vsync();
|
||||
memset(gp2x_screens[0], 0, 320*240*2);
|
||||
memset(gp2x_screens[1], 0, 320*240*2);
|
||||
gp2x_video_flip2(); // might flip to fb2/3
|
||||
gp2x_video_flip2(); // ..so we do it again
|
||||
}
|
||||
else
|
||||
gp2x_video_flip2();
|
||||
|
||||
// switch to 16bpp
|
||||
gp2x_video_changemode_ll(16);
|
||||
gp2x_video_RGB_setscaling(0, 320, 240);
|
||||
}
|
||||
|
||||
void plat_video_menu_begin(void)
|
||||
{
|
||||
g_menuscreen_ptr = g_screen_ptr;
|
||||
}
|
||||
|
||||
void plat_video_menu_end(void)
|
||||
{
|
||||
gp2x_video_flip2();
|
||||
}
|
||||
|
||||
void plat_early_init(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
FILE *f;
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
default_cpu_clock = 200;
|
||||
gp2x_dev_id = GP2X_DEV_GP2X;
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
default_cpu_clock = 533;
|
||||
f = fopen("/dev/accel", "rb");
|
||||
if (f) {
|
||||
printf("detected Caanoo\n");
|
||||
gp2x_dev_id = GP2X_DEV_CAANOO;
|
||||
fclose(f);
|
||||
}
|
||||
else {
|
||||
printf("detected Wiz\n");
|
||||
gp2x_dev_id = GP2X_DEV_WIZ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("could not recognize SoC, running in dummy mode.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// just use gettimeofday until plat_init()
|
||||
gp2x_get_ticks_ms = plat_get_ticks_ms_good;
|
||||
gp2x_get_ticks_us = plat_get_ticks_us_good;
|
||||
}
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
mmsp2_init();
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
pollux_init();
|
||||
break;
|
||||
default:
|
||||
dummy_init();
|
||||
break;
|
||||
}
|
||||
|
||||
warm_init();
|
||||
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
|
||||
// use buffer2 for menubg to save mem (using only buffers 0, 1 in menu)
|
||||
g_menubg_ptr = gp2x_screens[2];
|
||||
|
||||
// snd
|
||||
sndout_oss_init();
|
||||
|
||||
if (gp2x_dev_id == GP2X_DEV_CAANOO)
|
||||
in_set_config(in_name_to_id("evdev:pollux-analog"), IN_CFG_KEY_NAMES,
|
||||
caanoo_keys, sizeof(caanoo_keys));
|
||||
|
||||
gp2x_menu_init();
|
||||
}
|
||||
|
||||
void plat_finish(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
warm_finish();
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
mmsp2_finish();
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
pollux_finish();
|
||||
break;
|
||||
default:
|
||||
dummy_finish();
|
||||
break;
|
||||
}
|
||||
|
||||
sndout_oss_exit();
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define CASE_SENSITIVE_FS 1 // CS filesystem
|
||||
#define DONT_OPEN_MANY_FILES 0
|
||||
#define REDUCE_IO_CALLS 0
|
||||
#define SIMPLE_WRITE_SOUND 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 1
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define MSCREEN_SIZE_FIXED 1
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
|
||||
// pico.c
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
// logging emu events
|
||||
#define EL_LOGMASK (EL_STATUS)
|
||||
// (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL|EL_IDLE)
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "/"
|
||||
#define PATH_SEP_C '/'
|
||||
#define MENU_X2 0
|
||||
|
||||
#endif //PORT_CONFIG_H
|
|
@ -1,13 +0,0 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
@ .equiv START_ROW, 1
|
||||
@ .equiv END_ROW, 27
|
||||
@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
|
||||
.equiv START_ROW, 0
|
||||
.equiv END_ROW, 28
|
||||
|
||||
.equiv UNALIGNED_DRAWLINEDEST, 0
|
||||
|
||||
@ this should be set to one only for GP2X port
|
||||
.equiv EXTERNAL_YM2612, 1
|
||||
|
37
gp2x/test.c
37
gp2x/test.c
|
@ -1,37 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "gp2x.h"
|
||||
|
||||
void spend_cycles(int c);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct timeval tval; // timing
|
||||
int thissec = 0, frames_done = 0;
|
||||
|
||||
gp2x_init();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
gettimeofday(&tval, 0);
|
||||
|
||||
if(thissec != tval.tv_sec)
|
||||
{
|
||||
thissec = tval.tv_sec;
|
||||
|
||||
printf("frames_done: %i\n", frames_done);
|
||||
frames_done = 0;
|
||||
}
|
||||
|
||||
|
||||
//gp2x_video_wait_vsync();
|
||||
//usleep(1); // sleeps a minimum of ~20ms
|
||||
//gp2x_video_flip(); // can be called ~430000 times/sec
|
||||
spend_cycles(1000);
|
||||
frames_done++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#define VERSION "1.80"
|
||||
|
254
gp2x/warm.c
254
gp2x/warm.c
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* wARM - exporting ARM processor specific privileged services to userspace
|
||||
* userspace part
|
||||
*
|
||||
* Copyright (c) Gražvydas "notaz" Ignotas, 2009
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the organization nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define WARM_CODE
|
||||
#include "warm.h"
|
||||
|
||||
/* provided by glibc */
|
||||
extern long init_module(void *, unsigned long, const char *);
|
||||
extern long delete_module(const char *, unsigned int);
|
||||
|
||||
static int warm_fd = -1;
|
||||
static int kernel_version;
|
||||
|
||||
static void sys_cacheflush(void *start, void *end)
|
||||
{
|
||||
#ifdef __ARM_EABI__
|
||||
/* EABI version */
|
||||
int num = __ARM_NR_cacheflush;
|
||||
__asm__("mov r0, %0 ;"
|
||||
"mov r1, %1 ;"
|
||||
"mov r2, #0 ;"
|
||||
"mov r7, %2 ;"
|
||||
"swi 0" : : "r" (start), "r" (end), "r" (num)
|
||||
: "r0", "r1", "r2", "r3", "r7");
|
||||
#else
|
||||
/* OABI */
|
||||
__asm__("mov r0, %0 ;"
|
||||
"mov r1, %1 ;"
|
||||
"mov r2, #0 ;"
|
||||
"swi %2" : : "r" (start), "r" (end), "i" __ARM_NR_cacheflush
|
||||
: "r0", "r1", "r2", "r3");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Those are here because system() occasionaly fails on Wiz
|
||||
* with errno 12 for some unknown reason */
|
||||
static int manual_insmod_26(const char *fname, const char *opts)
|
||||
{
|
||||
unsigned long len, read_len;
|
||||
int ret = -1;
|
||||
void *buff;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(fname, "rb");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
buff = malloc(len);
|
||||
if (buff == NULL)
|
||||
goto fail0;
|
||||
|
||||
read_len = fread(buff, 1, len, f);
|
||||
if (read_len != len) {
|
||||
fprintf(stderr, "failed to read module\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
ret = init_module(buff, len, opts);
|
||||
|
||||
fail1:
|
||||
free(buff);
|
||||
fail0:
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int manual_rmmod(const char *name)
|
||||
{
|
||||
return delete_module(name, O_NONBLOCK|O_EXCL);
|
||||
}
|
||||
|
||||
int warm_init(void)
|
||||
{
|
||||
struct utsname unm;
|
||||
char buff1[32], buff2[128];
|
||||
int ret;
|
||||
|
||||
memset(&unm, 0, sizeof(unm));
|
||||
uname(&unm);
|
||||
|
||||
if (strlen(unm.release) < 3 || unm.release[1] != '.') {
|
||||
fprintf(stderr, "unexpected version string: %s\n", unm.release);
|
||||
goto fail;
|
||||
}
|
||||
kernel_version = ((unm.release[0] - '0') << 4) | (unm.release[2] - '0');
|
||||
|
||||
warm_fd = open("/proc/warm", O_RDWR);
|
||||
if (warm_fd >= 0)
|
||||
return 0;
|
||||
|
||||
snprintf(buff1, sizeof(buff1), "warm_%s.%s", unm.release, kernel_version >= 0x26 ? "ko" : "o");
|
||||
snprintf(buff2, sizeof(buff2), "/sbin/insmod %s verbose=1", buff1);
|
||||
|
||||
/* try to insmod */
|
||||
ret = system(buff2);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "system/insmod failed: %d %d\n", ret, errno);
|
||||
if (kernel_version >= 0x26) {
|
||||
ret = manual_insmod_26(buff1, "verbose=1");
|
||||
if (ret != 0)
|
||||
fprintf(stderr, "manual insmod also failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
warm_fd = open("/proc/warm", O_RDWR);
|
||||
if (warm_fd >= 0)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "wARM: can't init, acting as sys_cacheflush wrapper\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void warm_finish(void)
|
||||
{
|
||||
char name[32], cmd[64];
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0)
|
||||
return;
|
||||
|
||||
close(warm_fd);
|
||||
warm_fd = -1;
|
||||
|
||||
if (kernel_version < 0x26) {
|
||||
struct utsname unm;
|
||||
memset(&unm, 0, sizeof(unm));
|
||||
uname(&unm);
|
||||
snprintf(name, sizeof(name), "warm_%s", unm.release);
|
||||
}
|
||||
else
|
||||
strcpy(name, "warm");
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/rmmod %s", name);
|
||||
ret = system(cmd);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "system/rmmod failed: %d %d\n", ret, errno);
|
||||
manual_rmmod(name);
|
||||
}
|
||||
}
|
||||
|
||||
int warm_cache_op_range(int op, void *addr, unsigned long size)
|
||||
{
|
||||
struct warm_cache_op wop;
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0) {
|
||||
/* note that this won't work for warm_cache_op_all */
|
||||
sys_cacheflush(addr, (char *)addr + size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wop.ops = op;
|
||||
wop.addr = (unsigned long)addr;
|
||||
wop.size = size;
|
||||
|
||||
ret = ioctl(warm_fd, WARMC_CACHE_OP, &wop);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_CACHE_OP failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int warm_cache_op_all(int op)
|
||||
{
|
||||
return warm_cache_op_range(op, NULL, (unsigned long)-1);
|
||||
}
|
||||
|
||||
int warm_change_cb_range(int cb, int is_set, void *addr, unsigned long size)
|
||||
{
|
||||
struct warm_change_cb ccb;
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0)
|
||||
return -1;
|
||||
|
||||
ccb.addr = (unsigned long)addr;
|
||||
ccb.size = size;
|
||||
ccb.cb = cb;
|
||||
ccb.is_set = is_set;
|
||||
|
||||
ret = ioctl(warm_fd, WARMC_CHANGE_CB, &ccb);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_CHANGE_CB failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int warm_change_cb_upper(int cb, int is_set)
|
||||
{
|
||||
return warm_change_cb_range(cb, is_set, 0, 0);
|
||||
}
|
||||
|
||||
unsigned long warm_virt2phys(const void *ptr)
|
||||
{
|
||||
unsigned long ptrio;
|
||||
int ret;
|
||||
|
||||
ptrio = (unsigned long)ptr;
|
||||
ret = ioctl(warm_fd, WARMC_VIRT2PHYS, &ptrio);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_VIRT2PHYS failed");
|
||||
return (unsigned long)-1;
|
||||
}
|
||||
|
||||
return ptrio;
|
||||
}
|
||||
|
100
gp2x/warm.h
100
gp2x/warm.h
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* wARM - exporting ARM processor specific privileged services to userspace
|
||||
* library functions
|
||||
*
|
||||
* Copyright (c) Gražvydas "notaz" Ignotas, 2009
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the organization nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
#ifndef __WARM_H__
|
||||
#define __WARM_H__ 1
|
||||
|
||||
/* cache operations (warm_cache_op_*):
|
||||
* o clean - write dirty data to memory, but also leave in cache.
|
||||
* o invalidate - throw away everything in cache, losing dirty data.
|
||||
*
|
||||
* Write buffer is always drained, no ops will only drain WB
|
||||
*/
|
||||
#define WOP_D_CLEAN (1 << 0)
|
||||
#define WOP_D_INVALIDATE (1 << 1)
|
||||
#define WOP_I_INVALIDATE (1 << 2)
|
||||
|
||||
/* change C and B bits (warm_change_cb_*)
|
||||
* if is_set in not zero, bits are set, else cleared.
|
||||
* the address for range function is virtual address.
|
||||
*/
|
||||
#define WCB_C_BIT (1 << 0)
|
||||
#define WCB_B_BIT (1 << 1)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int warm_init(void);
|
||||
|
||||
int warm_cache_op_range(int ops, void *virt_addr, unsigned long size);
|
||||
int warm_cache_op_all(int ops);
|
||||
|
||||
int warm_change_cb_upper(int cb, int is_set);
|
||||
int warm_change_cb_range(int cb, int is_set, void *virt_addr, unsigned long size);
|
||||
|
||||
unsigned long warm_virt2phys(const void *ptr);
|
||||
|
||||
void warm_finish(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* internal */
|
||||
#ifdef WARM_CODE
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define WARM_IOCTL_BASE 'A'
|
||||
|
||||
struct warm_cache_op
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
int ops;
|
||||
};
|
||||
|
||||
struct warm_change_cb
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
int cb;
|
||||
int is_set;
|
||||
};
|
||||
|
||||
#define WARMC_CACHE_OP _IOW(WARM_IOCTL_BASE, 0, struct warm_cache_op)
|
||||
#define WARMC_CHANGE_CB _IOW(WARM_IOCTL_BASE, 1, struct warm_change_cb)
|
||||
#define WARMC_VIRT2PHYS _IOWR(WARM_IOCTL_BASE, 2, unsigned long)
|
||||
|
||||
#endif /* WARM_CODE */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
#endif /* __WARM_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue