remove PicoDrive-specific stuff, add readme

This commit is contained in:
notaz 2012-09-08 20:31:36 +03:00 committed by Grazvydas Ignotas
parent ca69c3e5a0
commit f506842df2
73 changed files with 13 additions and 16178 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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/

View file

@ -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 = &currentConfig.renderer32x;
else
r = &currentConfig.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);
}

View file

@ -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(&ltime);
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);
}

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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++;
}
}

View file

@ -1,2 +0,0 @@
#define VERSION "1.80"

View file

@ -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;
}

View file

@ -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__ */