Compare commits

...

38 commits
v0.6 ... master

Author SHA1 Message Date
tpunix
65d8764c24
Merge pull request #271 from bucanero/master
Saroo single save improvements
2025-02-14 11:06:20 +08:00
Damian Parrino
ab39208147 add crc32
- add crc32 checksum at offset 0x0C
- use ".SRO" file extension for Saroo single saves
2025-01-27 11:27:29 -03:00
tpunix
4d1928b285
Merge pull request #269 from bucanero/master
Add support for .BUP save format (import/export) to savetool
2025-01-27 11:23:17 +08:00
Damian Parrino
4a3cb6d640 update 2025-01-24 19:37:11 -03:00
Damián Parrino
058f1f1e77
Update bup_format.h 2025-01-24 19:14:15 -03:00
Damian Parrino
44730ba369 add .BUP format support
Vmem format
2025-01-22 11:51:07 -03:00
tpu
6d213af4a4 检测LOADDISC的返回值 2024-12-23 23:33:32 +08:00
tpu
a17c95943f 封面显示bugfix 2024-12-23 23:32:35 +08:00
tpu
b57308e76d 增加非游戏文件的处理 2024-12-22 22:52:53 +08:00
tpu
125911fb40 调整封面数据的校验和 2024-12-22 21:27:26 +08:00
tpu
329ca231c5 自动建立obj目录 2024-12-21 22:46:42 +08:00
tpu
8cca7ed9a5 增加区域文件 2024-12-21 22:33:50 +08:00
tpu
589832f159 更新sysid,支持全区域运行 2024-12-21 22:31:53 +08:00
tpu
319d454f31 按Z以系统光驱模式加载二进制文件 2024-12-21 22:30:31 +08:00
tpu
dc4b03008c 更新game_patch 2024-12-21 22:23:37 +08:00
tpu
295dc605cd BIOS兼容性增强 2024-12-21 22:22:36 +08:00
tpu
a7f540030a 增加刻录盘的支持 2024-12-21 22:19:51 +08:00
tpu
5033fd1107 修复背景与封面偶尔冲突的bug 2024-12-21 21:49:14 +08:00
tpu
1805e1e7a2 load_disc bugfix 2024-12-21 21:48:52 +08:00
tpu
0cd298759e 忽略cue中不支持的tag 2024-12-21 21:38:58 +08:00
tpu
b0569a920d typo fixup 2024-12-21 21:37:26 +08:00
tpu
5fa7c1618e 增加显示游戏封面功能 2024-10-13 19:56:04 +08:00
tpu
1dcffe12f0 支持V-Saturn 1.00的BIOS 2024-10-13 18:42:13 +08:00
tpu
eb48c664d6 支持系统存档与外置存储卡共存 2024-10-13 18:41:24 +08:00
tpu
b5fd8ac829 优化菜单显示 2024-10-13 18:35:21 +08:00
tpu
23264ff52a 使用dma优化memcpy 2024-10-13 18:28:00 +08:00
tpu
2b0a33e2e3 启动时显示SAROO的logo 2024-10-13 18:24:27 +08:00
tpu
8687c46d6b 优化按键轮询的间隔时间 2024-10-13 18:23:22 +08:00
tpu
6f6e18289b 增加常用日文汉字编码
增加希腊语字库
2024-10-12 20:17:57 +08:00
tpunix
459f05ffab
Merge pull request #203 from notcbw/newglyphs
添加一些缺失字形
2024-10-09 22:27:45 +08:00
tpunix
02a50799fc
Merge pull request #197 from aravikusu/master
Add Swedish language
2024-10-09 22:23:25 +08:00
tpunix
0dc8087d59
Merge branch 'master' into master 2024-10-09 22:23:12 +08:00
tpunix
20dd55f93a
Merge pull request #159 from PoliPyc/Polish_translation
Add Polish language
2024-10-09 22:17:19 +08:00
Bowen Cui
f9cde76cb2 add additional kanji/hanzi glyphs 2024-10-05 20:54:17 +08:00
Aravix
4f20b3f270 Add Swedish language 2024-09-13 02:06:39 +02:00
poliakustyczny
791f28ff3c Added polish translation for SAROO menu 2024-07-06 23:02:49 +02:00
tpu
d335365d27 修复read_file的bug 2024-06-28 23:22:07 +08:00
tpu
c8e9ea024f 更新game_patch 2024-06-28 23:21:42 +08:00
43 changed files with 41339 additions and 917 deletions

View file

@ -303,7 +303,7 @@ int sd_read_sector(u32 start, int size, u8 *buf)
if(sd_rca==0)
return -1;
if(type==0x24){
if(type==0x24 || type==0x61){
return sd_read_blocks(start, size, buf);
}
@ -330,7 +330,7 @@ int sd_write_sector(u32 start, int size, u8 *buf)
if(sd_rca==0)
return -1;
if(type==0x24){
if(type==0x24 || type==0x61){
return sd_write_blocks(start, size, buf);
}

View file

@ -409,7 +409,7 @@ void fpga_config(void)
break;
osDelay(1);
}
if(i==10){
if(i==100){
printk("FPGA config timeout!\n");
led_event(LEDEV_FPGA_ERROR);
}else{

View file

@ -114,6 +114,7 @@
#define SSCMD_LMEMS 0x000b
#define SSCMD_SMEMS 0x000c
#define SSCMD_STARTUP 0x000d
#define SSCMD_SELECT 0x000e
#define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f)
@ -302,6 +303,7 @@ extern int next_disc;
extern int sort_mode;
extern int category_num;
extern int category_current;
extern int total_disc;
/******************************************************************************/
@ -375,6 +377,7 @@ int list_disc(int cid, int show);
int load_disc(int index);
int load_pcm(char *fname);
int unload_disc(void);
int get_disc_ip(int index, u8 *ipbuf);
int open_savefile(void);
int load_savefile(char *gameid);
@ -391,5 +394,9 @@ void gif_decode_timer(void);
void gif_decode_exit(void);
void cover_init(void);
void load_cover(int index);
/******************************************************************************/

View file

@ -98,7 +98,7 @@ int parse_iso(char *fname)
}
int parse_cue(char *fname)
int parse_cue(char *fname, u8 *ipbuf)
{
FIL fp;
u8 *fbuf = (u8*)0x2400b000;
@ -144,6 +144,19 @@ int parse_cue(char *fname)
return -5;
sprintk(full_path, "%s/%s", dir_name, tfile);
if(ipbuf){
// 如果ipbuf存在则意味着只需读IP信息。在第一个FILE里面。
tk_fp = &track_fp[99];
retv = f_open(tk_fp, full_path, FA_READ);
if(retv){
return -6;
}
retv = f_read(tk_fp, ipbuf, 256, &nread);
f_close(tk_fp);
return retv;
}
if(tno!=-1){
// close last track
tk = &cdb.tracks[tno];
@ -226,7 +239,7 @@ int parse_cue(char *fname)
}else if(strcmp(token, "REM")==0){
}else if(strcmp(token, "FLAGS")==0){
}else{
return -10;
//return -10;
}
}
@ -469,8 +482,9 @@ int load_disc(int index)
char *fname;
char cat_dir[256];
unload_disc();
current_index = 0;
if((index&0xffff)==0xffff){
return -1;
}
if(disc_path[index]==0){
printk("Invalid disc index %d\n", index);
@ -485,12 +499,18 @@ int load_disc(int index)
fname = malloc(256);
retv = find_cue_iso(cat_dir, fname);
if(retv<0)
if(retv<=0){
if(retv==0)
retv = -2;
goto _exit;
}
unload_disc();
current_index = 0;
printk("Load disc: {%s}\n", fname);
if(retv==1){
retv = parse_cue(fname);
retv = parse_cue(fname, NULL);
}else{
retv = parse_iso(fname);
}
@ -544,3 +564,44 @@ _exit:
return retv;
}
int get_disc_ip(int index, u8 *ipbuf)
{
int retv;
char *fname;
char cat_dir[256];
if(disc_path[index]==0){
printk("Invalid disc index %d\n", index);
return -1;
}
if(category_num){
sprintk(cat_dir, "/SAROO/ISO/%s/%s", get_category(category_current), path_str+disc_path[index]);
}else{
sprintk(cat_dir, "/SAROO/ISO/%s", path_str+disc_path[index]);
}
fname = malloc(256);
retv = find_cue_iso(cat_dir, fname);
if(retv<=0){
if(retv==0)
retv = -2;
goto _exit;
}else if(retv==1){
retv = parse_cue(fname, ipbuf);
}else{
FIL *fp = &track_fp[99];
retv = f_open(fp, fname, FA_READ);
if(retv)
goto _exit;
u32 nread;
retv = f_read(fp, ipbuf, 256, &nread);
f_close(fp);
}
_exit:
free(fname);
return retv;
}

View file

@ -636,6 +636,9 @@ void ss_cmd_handle(void)
// 镜像列表
list_disc(0, 0);
// 封面数据
cover_init();
// 背景音乐
int audio_repeat = 0;
retv = load_pcm("/SAROO/bgsound.pcm");
@ -660,10 +663,26 @@ void ss_cmd_handle(void)
cdb.play_type = PLAYTYPE_SECTOR;
disk_task_wakeup();
}
TIM6->CR1 = 0x0005;
gif_decode_init();
break;
}
case SSCMD_SELECT: {
int index = SS_ARG;
printk("\nSelect %04x\n", index);
if(index&0x8000){
gif_decode_exit();
}
if(index&0x4000){
gif_decode_init();
}else{
load_cover(index);
}
break;
}
default:
SSLOG(_INFO, "[SS] unkonw cmd: %04x\n", cmd);
break;

View file

@ -8,6 +8,23 @@
/******************************************************************************/
u32 adler32(u8 *data, int len)
{
u32 a = 1, b = 0;
int i;
for(i=0; i<len; i++) {
a = (a + data[i]) % 65521;
b = (b + a) % 65521;
}
return (b<<16) | a;
}
/******************************************************************************/
// 将gameid分解为id与ver
static char *gameid_split(char *gid)
{
@ -623,3 +640,169 @@ int flush_smems(int flag)
/******************************************************************************/
static FIL cover_fp;
static int cover_inited = 0;
static int *ip_cache_table[12];
static int *ip_cache_ptr;
static int find_cover(char *gid, int fsum)
{
u8 *cover_buf = (u8*)0x614f0000;
int i;
for(i=0; i<2048; i++){
u8 *hdr = cover_buf+i*32;
if(hdr[0]==0)
break;
if(strcmp((char*)hdr, gid))
continue;
if(*(u32*)(hdr+12)!=fsum)
continue;
return (int)hdr;
}
return -1;
}
static int last_chdr;
// 初始化COVER数据
void cover_init(void)
{
int i, retv;
u32 nread;
retv = f_open(&cover_fp, "/SAROO/cover.bin", FA_READ);
if(retv!=FR_OK){
// 打开cover.bin失败.
cover_inited = -1;
return;
}
// 读cover.bin的头部到0x6140f000处。
f_read(&cover_fp, (u8*)0x614f0000, 0x10000, &nread);
// ip_cache存放游戏index到cover的映射.
ip_cache_ptr = (int*)(0x614e0000);
memset((u8*)0x614e0000, 0, 2560*4);
// 每个类别有一个指向ip_cache的指针.
for(i=0; i<12; i++){
ip_cache_table[i] = NULL;
}
memset((u8*)0x61400100, 0, 324*240);
cover_inited = 1;
last_chdr = -1;
}
void load_cover(int index)
{
int i, retv;
u32 nread;
if(index&0x8000){
last_chdr = -1;
}
index &= 0x7fff;
if(cover_inited<0){
// 无cover.bin
return;
}
// 取得当前类别的ip_cache指针.
int *ip_cache = ip_cache_table[category_current];
if(ip_cache==NULL){
// 初始化当前类别的指针
ip_cache_table[category_current] = ip_cache_ptr;
ip_cache = ip_cache_ptr;
ip_cache_ptr += total_disc;
}
// 获得cover头部指针
int chdr = ip_cache[index];
if(chdr==-1){
// 该游戏没有cover.
printk(" No Cover!\n");
goto _no_cover;
}else if(chdr==0){
// 第一次选择该游戏建立cache
u8 ipbuf[256];
char gid[16];
retv = get_disc_ip(index, ipbuf);
if(retv<0){
printk(" get_disc_ip failed!\n");
ip_cache[index] = -1;
goto _no_cover;
}
u8 *ip = ipbuf;
if(strncmp((char*)ipbuf, "SEGA SEGASATURN ", 16)){
ip = ipbuf+0x10;
}
memcpy(gid, ip+0x20, 16);
char *p = strrchr(gid, 'V');
if(p)
*p = 0;
p = strchr(gid, ' ');
if(p)
*p = 0;
int fsum = adler32(ip+0x30, 64);
chdr = (int)find_cover(gid, fsum);
if(chdr<0){
printk(" No Cover Found! {%12s} {%08x}\n", gid, fsum);
ip_cache[index] = -1;
goto _no_cover;
}
ip_cache[index] = chdr;
}
if(chdr==last_chdr)
return;
last_chdr = chdr;
int w = *(u16*)(chdr+0x14);
int h = *(u16*)(chdr+0x16);
int offset = *(int*)(chdr+0x10);
f_lseek(&cover_fp, offset);
f_read(&cover_fp, (u8*)0x61400c00, w*h+0x0400, &nread);
memcpy((u8*)0x61400100, (u8*)0x61400c00, 0x0400);
*(u16*)(0x61400004) = w;
*(u16*)(0x61400006) = h;
*(u16*)(0x61400008) = 0;
*(u16*)(0x6140000a) = 0;
*(u16*)(0x6140000c) = 176;
*(u16*)(0x6140000e) = (h>128)? 24 : 88;
*(u8*)0x61400000 = 3;
*(u8*)0x61400002 = 1;
return;
_no_cover:
last_chdr = -1;
*(u16*)(0x61400004) = 128;
*(u16*)(0x61400006) = 128;
*(u16*)(0x61400008) = 0;
*(u16*)(0x6140000a) = 0;
*(u16*)(0x6140000c) = 176;
*(u16*)(0x6140000e) = 88;
memset((u8*)0x61401000, 0, 128*192);
*(u8*)0x61400000 = 4;
return;
}
/******************************************************************************/

View file

@ -108,6 +108,12 @@ static u8 *gif_decode_clip(GIF_DECODER *gd)
gd->lflag = p[9];
//printk("lflag: %02x\n", gd->lflag);
//printk("lres: (%d,%d) %dx%d\n", gd->l_x, gd->l_y, gd->l_width, gd->l_height);
*(u16*)(0x61400004) = gd->l_width;
*(u16*)(0x61400006) = gd->l_height;
*(u16*)(0x61400008) = gd->l_x;
*(u16*)(0x6140000a) = gd->l_y;
if(gd->lflag&0x80){
// local palete
int pal_num = 1<<((gd->lflag&7)+1);
@ -290,6 +296,11 @@ static void gifb_put_pixel(GIF_DECODER *gd, int x, int y, int val)
}
#define SCR_W 320
#define SCR_H 240
static int in_decoding;
void gif_decode_init(void)
{
FIL fp;
@ -299,10 +310,21 @@ void gif_decode_init(void)
*(u32*)(0x61400000) = 0;
memset(gd, 0, sizeof(GIF_DECODER));
in_decoding = 0;
retv = f_open(&fp, "/SAROO/mainmenu_bg.gif", FA_READ);
if(retv!=FR_OK){
gd_state = -1;
// 无背景时做一次清屏
*(u16*)(0x61400004) = 128;
*(u16*)(0x61400006) = 128;
*(u16*)(0x61400008) = 0;
*(u16*)(0x6140000a) = 0;
*(u16*)(0x6140000c) = 176;
*(u16*)(0x6140000e) = 88;
memset((u8*)0x61401000, 0, 128*192);
*(u8*)0x61400000 = 4;
return;
}
@ -320,48 +342,65 @@ void gif_decode_init(void)
*(u16*)(0x61400004) = gd->width;
*(u16*)(0x61400006) = gd->height;
*(u16*)(0x61400008) = 0;
*(u16*)(0x6140000a) = 0;
// gif图片居中放置
*(u16*)(0x6140000c) = (SCR_W - gd->width)/2;
*(u16*)(0x6140000e) = (SCR_H - gd->height)/2;
gd_state = 0;
}
static void change_gd_state(int oldval, int newval)
{
__sync_val_compare_and_swap(&gd_state, oldval, newval);
}
void gif_decode_timer(void)
{
GIF_DECODER *gd = &g_gd;
if(gd_state==0){
// 解码一帧图像
//int start = osKernelGetTickCount();
in_decoding = 1;
//TIM6->CR1 = 0x0005;
//int start = TIM6->CNT;
int eof = gif_decode_frame(gd);
//start = osKernelGetTickCount()-start;
//printk("gif_decode_frame: %d\n", start);
in_decoding = 0;
//start = TIM6->CNT-start;
//printk("gif_decode_frame: %d us\n", start*10);
if(gd_state<0)
return;
if(eof){
if(gd->frames>1){
gd->iptr = 0;
gd->frames = 0;
}else{
gd_state = -2;
change_gd_state(0, -2);
}
}else{
gd->frames += 1;
gd_state = 1;
change_gd_state(0, 1);
// 通知SS来取
*(u8*)0x61400000 = 1;
}
}else if(gd_state==1){
if(*(u8*)0x61400000==0){
// SS显示完毕会清标志位
gd_state = 2;
if(gd->delay){
gd->gtimer = osKernelGetTickCount() + gd->delay;
gd_state = 2;
change_gd_state(1, 2);
}else{
gd_state = 0;
change_gd_state(1, 0);
}
}
}else if(gd_state==2){
if(osKernelGetTickCount() >= gd->gtimer){
gd_state = 0;
change_gd_state(2, 0);
}
}
}
@ -369,13 +408,13 @@ void gif_decode_timer(void)
void gif_decode_exit(void)
{
gd_state = -1;
__sync_lock_test_and_set(&gd_state, -1);
while(in_decoding){
osDelay(1);
}
}
/******************************************************************************/

View file

@ -756,7 +756,7 @@
<Group>
<GroupName>FatFS</GroupName>
<tvExp>0</tvExp>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>

View file

@ -33,7 +33,10 @@ OBJ = obj/crt0.o \
obj/tiny_xm.o \
obj/version.o
all : BUILD_VER $(EXE)
all : obj BUILD_VER $(EXE)
obj:
mkdir obj
BUILD_VER:
touch version.c

View file

@ -84,17 +84,17 @@ int cdc_cmd(int wait, CDCMD *cmd, CDCMD *resp, char *cmdname)
resp->cr4 = CR4;
if((resp->cr1>>8)==0xff){
printk("CMD REJECT!\n");
//printk("CMD REJECT!\n");
return -5;
}
if((resp->cr1>>8)&0x80){
printk("CMD WAIT!\n");
printk("CMD WAIT! HIRQ=%04x CR1=%04x %s\n", HIRQ, resp->cr1, cmdname);
return -6;
}
if(wait){
if(wait_hirq(wait)){
printk("HIRQ TIMEOUT! HIRQ=%04x wait=%04x\n", HIRQ, wait);
printk("HIRQ TIMEOUT! HIRQ=%04x wait=%04x %s\n", HIRQ, wait, cmdname);
}
}
//clear_hirq(wait|HIRQ_CMOK);
@ -484,6 +484,22 @@ int cdc_get_del_data(int bufnum, int spos, int snum)
return cdc_cmd(HIRQ_DRDY, &cmd, &resp, "cdc_get_del_data");
}
int cdc_put_data(int bufnum, int snum)
{
CDCMD cmd, resp;
cmd.cr1 = 0x6400;
cmd.cr2 = 0x0000;
cmd.cr3 = bufnum<<8;
cmd.cr4 = snum;
return cdc_cmd(0, &cmd, &resp, "cdc_put_data");
}
void cdc_trans_data(u8 *buf, int length)
{
int i;
@ -521,7 +537,7 @@ int cdc_auth_device(void)
CDCMD cmd, resp;
int status;
printk("\n\nCD_AUTH ... HIRQ=%04x\n", HIRQ);
//printk("\n\nCD_AUTH ... HIRQ=%04x\n", HIRQ);
cmd.cr1 = 0xe000;
cmd.cr2 = 0x0000;
@ -617,7 +633,8 @@ int cdc_read_file(int selnum, int fid, int offset)
cmd.cr3 = (selnum<<8) | ((fid>>16)&0xff);
cmd.cr4 = fid&0xffff;
return cdc_cmd(HIRQ_EFLS, &cmd, &resp, "cdc_read_file");
return cdc_cmd(0, &cmd, &resp, "cdc_read_file");
// return cdc_cmd(HIRQ_EFLS, &cmd, &resp, "cdc_read_file");
}
@ -637,6 +654,140 @@ int cdc_abort_file(void)
/**********************************************************/
void cdc_auth_hram(CDCMD *resp, int delay)
{
int status;
// cdc_put_data(0, 150);
HIRQ = ~(HIRQ_CMOK|HIRQ_EHST);
CR1 = 0x6400;
CR2 = 0x0000;
CR3 = 0x0000;
CR4 = 150;
while(HIRQ&HIRQ_CMOK);
resp->cr1 = CR1;
resp->cr2 = CR2;
resp->cr3 = CR3;
resp->cr4 = CR4;
status = resp->cr1>>8;
if(status&0x80){
printk("CMD WAIT! HIRQ=%04x status=%02x cdc_put_data\n", HIRQ, status);
}
for(int i=0; i<2352*150; i+=4){
REG(0x25818000) = 0x00020002;
}
// cdc_end_trans
HIRQ = ~(HIRQ_CMOK|HIRQ_EHST);
CR1 = 0x0600;
CR2 = 0x0000;
CR3 = 0x0000;
CR4 = 0x0000;
while(HIRQ&HIRQ_CMOK);
resp->cr1 = CR1;
resp->cr2 = CR2;
resp->cr3 = CR3;
resp->cr4 = CR4;
status = resp->cr1>>8;
if(status&0x80){
printk("CMD WAIT! HIRQ=%04x status=%02x cdc_end_trans\n", HIRQ, status);
}
while(HIRQ&HIRQ_EHST);
HIRQ = ~(HIRQ_DRDY);
for(int i=0; i<delay; i++){
__asm volatile("":::"memory"); // 防止被gcc优化掉
}
// cdc_move_data(0,0,0,50);
HIRQ = ~(HIRQ_CMOK);
CR1 = 0x6600;
CR2 = 0x0000;
CR3 = 0x0000;
CR4 = 50;
while(HIRQ&HIRQ_CMOK);
resp->cr1 = CR1;
resp->cr2 = CR2;
resp->cr3 = CR3;
resp->cr4 = CR4;
status = resp->cr1>>8;
if(status&0x80){
printk("CMD WAIT! HIRQ=%04x status=%02x cdc_put_data\n", HIRQ, status);
}
// cdc_auth
HIRQ = ~(HIRQ_CMOK|HIRQ_DCHG|HIRQ_EFLS);
CR1 = 0xe000;
CR2 = 0x0000;
CR3 = 0x0000;
CR4 = 0x0000;
while(HIRQ&HIRQ_CMOK);
resp->cr1 = CR1;
resp->cr2 = CR2;
resp->cr3 = CR3;
resp->cr4 = CR4;
status = resp->cr1>>8;
if(status&0x80){
printk("CMD WAIT! HIRQ=%04x status=%02x cdc_auth\n", HIRQ, status);
}
while(HIRQ&HIRQ_EFLS);
}
int jhl_auth_hack(int delay)
{
int status;
CDCMD resp;
memcpy((u8*)0x06080000, cdc_auth_hram, 0x400);
void (*go)(CDCMD*, int) = (void*)0x06080000;
#if 1
while(1){
status = (CR1>>8)&0x0f;
if(status>=STATUS_OPEN){
printk("State error! %04x\n", status);
return status;
}
if(status==STATUS_PAUSE)
break;
}
#endif
cdc_set_size(3);
go(&resp, delay);
int old = 0xffffffff;
while(1){
for(int i=0; i<100000; i++){ }
cdc_get_status(&status);
if(status!=old){
printk("stat: %04x\n", status);
}
old = status;
status &= 0x0f;
if(status==STATUS_FATAL)
break;
if(status==STATUS_PAUSE)
break;
if(status==STATUS_OPEN || status==STATUS_NODISC){
return -1;
}
}
cdc_auth_status(&status);
printk("AUTH: %02x\n\n", status);
cdc_set_size(0);
return status;
}
/**********************************************************/
void cdc_init(void)
{
cdc_abort_file();
@ -644,7 +795,20 @@ void cdc_init(void)
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
#if 0
cdc_auth_device();
int status;
cdc_auth_status(&status);
if(status==3){
for(int i=0; i<8; i++){
status = jhl_auth_hack(10000);
if(status==2)
break;;
}
}
#endif
}
@ -777,6 +941,9 @@ void cdc_file_test(void)
cdc_get_file_scope(&fid, &fnum, &drend);
printk("file scope: fid=%d fnum=%d drend=%d\n", fid, fnum, drend);
cdc_get_file_info(0xffffff, finfo);
if(fnum>254){
fnum = 254;
}
for(i=0; i<fnum; i++){
printk("file %4d: fad=%08x size=%08x %02x %02x %02x %02x\n", i,
finfo[i].fad, finfo[i].size,
@ -789,15 +956,13 @@ void cdc_file_test(void)
do{
cdc_get_numsector(1, &free);
printk("cdc_get_numsector 1: %d HIRQ=%04x\n", free, HIRQ);
}while(free<200);
}while(free==0);
cdc_get_buffer_size(&total, &npart, &free);
printk("cdc_get_buffer_size: free=%d\n", free);
cdc_get_del_data(1, 0, 128);
cdc_get_numsector(1, &free);
printk("cdc_get_numsector 1: %d\n", free);
cdc_trans_data(sbuf, 2048*100);
cdc_get_del_data(1, 0, free);
cdc_trans_data(sbuf, 2048*free);
cdc_end_trans(NULL);
while(1){
@ -806,7 +971,6 @@ void cdc_file_test(void)
break;
}
cdc_get_numsector(1, &free);
printk("cdc_get_numsector 1: %d HIRQ=%04x\n", free, HIRQ);
cdc_get_buffer_size(&total, &npart, &free);

View file

@ -33,11 +33,62 @@ int fbw = 320;
int fbh = 240;
u8 *fbptr = (u8*)VDP2_VRAM;
#include "slogo.h"
void logo_trans(void)
{
#if 1
int i, j;
if(*(u16*)(VDP2_VRAM+0x0848)!=0x000d || *(u16*)(VDP2_VRAM+0x084c)!=0x000d)
return;
for(i=0; i<16; i++){
MZCTL = (i<<12) | (i<<8) | 0x0001;
for(j=0; j<300000; j++){};
}
memcpy((void*)VDP2_VRAM+0x4000, logo_dat+32, size_logo_dat-32);
memcpy((void*)VDP2_CRAM, logo_dat, 32);
memset((void*)VDP2_VRAM+0x6000, 0, 64*64*2);
j = 9;
i = 11;
int cid = 0x0200;
u16 *pt = (u16*)(VDP2_VRAM+0x6000+(j*64+i)*2);
for(j=0; j<6; j++){
for(i=0; i<20; i++){
pt[i] = cid;
cid += 1;
}
pt += 64;
}
for(i=14; i>=0; i--){
MZCTL = (i<<12) | (i<<8) | 0x0001;
for(j=0; j<300000; j++){};
}
MZCTL = 0;
for(j=0; j<5000000; j++){};
CCCTL = 0x0001;
for(i=0; i<32; i++){
CCRNA = i;
for(j=0; j<300000; j++){};
}
CCCTL = 0x0000;
#endif
}
void vdp_init(void)
{
int i;
volatile unsigned int *vdp2_cram = (volatile unsigned int*)VDP2_CRAM;
logo_trans();
// Disable VDP1
VDP1_REG_PTMR = 0;
*((volatile u16 *)(VDP1_RAM)) = 0x8000;
@ -125,6 +176,26 @@ void nbg1_put_pixel(int x, int y, int color)
}
void vdp2_win0(int scr, int outside, int sx, int sy, int ex, int ey)
{
if(scr==-1){
WCTLA = 0;
return;
}
WPSX0 = sx<<1;
WPSY0 = sy;
WPEX0 = ex<<1;
WPEY0 = ey;
if(scr==0){
WCTLA = 0x0002 | (outside);
}else{
WCTLA = 0x0200 | (outside<<8);
}
}
/******************************************************************************/
@ -176,9 +247,6 @@ static u8 *find_font(int ucs)
{
u8 *fdat;
if(ucs==0x30fc)
ucs = 0x2014; // gb2312没有'ー'这个符号用A1AA(U2014)代替。
fdat = find_ucs(font_latin, ucs);
if(fdat==NULL){
fdat = find_ucs((u8*)font_cjk, ucs);
@ -408,6 +476,10 @@ void put_box(int x1, int y1, int x2, int y2, int c)
/******************************************************************************/
#define PAD_REPEAT_TIME 500
#define PAD_REPEAT_RATE 100
static u32 last_pdat = 0;
static u32 last_value;
static u32 curr_pdat = 0;
@ -448,24 +520,19 @@ u32 conio_getc(void)
if(curr_pdat){
// 转入重复状态
pdat_state = 3;
pdat_count = 0;
pdat_wait = 500;
pdat_wait = get_timer() + MS2TICK(PAD_REPEAT_TIME);
}else{
pdat_state = 0;
}
last_value = (pdat<<16) | curr_pdat;
//printk("key0: %08x\n", last_value);
return last_value;
case 3:
// 重复状态
if(pdat != curr_pdat){
pdat_state = 0;
}else{
pdat_count += 1;
if(pdat_count==pdat_wait){
pdat_wait = 30;
pdat_count = 0;
//printk("keyr: %08x\n", last_value);
if(get_timer()>=pdat_wait){
pdat_wait = PAD_REPEAT_RATE;
return last_value;
}
}
@ -521,10 +588,11 @@ static void draw_menu_item(int index, char *item, int select)
static int draw_menu_item_select(int index, char *item)
{
int x, y = 24+index*16;
int x;
int color = 0x8f;
int i, adv;
//int y = 24+index*16;
//put_box(MENU_LB, y, MENU_RB, y+16-1, (color&0x0f));
memset(sel_pbuf, (color&0x0f), llen*16);
@ -553,7 +621,12 @@ static void put_select_item(int index)
u8 *src = sel_pbuf+MENU_LB;
for(i=0; i<16; i++){
#if 0
memcpy(dst, src, (MENU_RB-MENU_LB+1));
#else
//cpu_dmemcpy(dst, src, (MENU_RB-MENU_LB+1), 0);
scu_dmemcpy(dst, src, (MENU_RB-MENU_LB+1), 0);
#endif
dst += llen;
src += llen;
}
@ -641,13 +714,20 @@ static void sel_init(MENU_DESC *menu)
}
void menu_update(MENU_DESC *menu)
void menu_update(MENU_DESC *menu, int new)
{
int i, select;
for(i=0; i<menu->num; i++){
select = (i==menu->current)? 1: 0;
draw_menu_item(i, menu->items[i], select);
if(new>=0){
int old = menu->current;
menu->current = new;
draw_menu_item(old, menu->items[old], 0);
draw_menu_item(new, menu->items[new], 1);
}else{
for(i=0; i<menu->num; i++){
select = (i==menu->current)? 1: 0;
draw_menu_item(i, menu->items[i], select);
}
}
menu_status(menu, NULL);
@ -664,7 +744,7 @@ void draw_menu_frame(MENU_DESC *menu)
put_hline( 22, 0, fbw-1, 0x0f);
put_hline(217, 0, fbw-1, 0x0f);
menu_update(menu);
menu_update(menu, -1);
if(menu->version){
menu_status(menu, menu->version);
}
@ -695,14 +775,12 @@ int menu_default(MENU_DESC *menu, int ctrl)
{
if(BUTTON_DOWN(ctrl, PAD_UP)){
if(menu->current>0){
menu->current -= 1;
menu_update(menu);
menu_update(menu, menu->current-1);
}
return 1;
}else if(BUTTON_DOWN(ctrl, PAD_DOWN)){
if(menu->current<(menu->num-1)){
menu->current += 1;
menu_update(menu);
menu_update(menu, menu->current+1);
}
return 1;
}else{

View file

@ -24,21 +24,21 @@ start:
_func_table:
.long 0x00000000
.long 0x00000004
.long 0x00000008
.long 0x0000000c
.long 0x00000010
.long 0x00000014
.long 0x00000018
.long 0x0000001c
.long 0x00000020
.long 0x00000024
.long 0x00000028
.long 0x0000002c
.long 0x00000030
.long 0x00000034
.long 0x00000038
.long 0x0000003c
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
_next_start:
! Disable interrupts

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -5,16 +5,94 @@
/**********************************************************/
static int my_bios_loadcd_boot(int r4, int r5);
static int (*cdp_boot_game)(void);
static int sk0, sk1;
static int bios_ver;
static int force_no_bup = 0;
static int disc_type;
void (*sys_bup_init)(u8*, u8*, void*);
int use_sys_load = 0;
static void (*orig_func)(void);
int my_bios_loadcd_read(void);
int my_bios_loadcd_init(void);
/**********************************************************/
static int ipstat = -1;
static int cdp_auth(void)
{
if(ipstat<0){
ipstat = 0;
}
int cdstat = (CR1>>8)&0x0f;
printk("cdp_auth: ipstat=%d cdstat=%02x\n", ipstat, cdstat);
if(cdstat==STATUS_OPEN || cdstat==STATUS_NODISC){
// 开盖了
return -2;
}
if(cdstat>=STATUS_RETRY){
// 发生错误,复位重试
ipstat = 0;
}
if(ipstat==0){
// 复位cdblock
cdblock_off();
cdblock_on(0);
ipstat = 1;
}else if(ipstat==1){
// 等待cdblock进入工作状态
if(cdstat==STATUS_PAUSE){
my_bios_loadcd_init();
ipstat = 2;
}
}else if(ipstat==2){
// 等待reset_selector完成
if(cdstat==STATUS_PAUSE){
ipstat = 3;
}
}else if(ipstat>=3 && ipstat<11){
// 执行伪认证重试8次
int retv = jhl_auth_hack(100000);
if(retv==2){
ipstat = 12;
}else{
ipstat += 1;
}
}else if(ipstat==11){
// 认证失败
ipstat = 0;
return -1;
}else if(ipstat>=12 && ipstat<16){
// 读IP重试4次
int retv = my_bios_loadcd_read();
if(retv==0){
ipstat = 0;
return 0;
}
ipstat += 1;
}else{
// 读IP失败
ipstat = 0;
return -2;
}
return 1;
}
/**********************************************************/
static void cdp_hook(void)
{
sk0 = *(u16*)0x06020232;
@ -29,6 +107,10 @@ static void hook_getkey(void)
if(*(u32*)(0x0604cd18) == 0x0604406c){
orig_func = (void*)0x0604406c;
*(u32*)(0x0604cd18) = (u32)cdp_hook;
}else if(*(u32*)(0x0604ccf4) == 0x0604406c){
// V-Saturn 1.00
orig_func = (void*)0x0604406c;
*(u32*)(0x0604ccf4) = (u32)cdp_hook;
}
}else if(bios_ver==1){
if(*(u32*)(0x0604d8e0) == 0x06044204){
@ -46,6 +128,10 @@ static void hook_getkey(void)
// 1.01a(U)
orig_func = (void*)0x06044ae0;
*(u32*)(0x0604ed0c) = (u32)cdp_hook;
}else if(*(u32*)(0x0604ed28) == 0x06044ae0){
// Samsung-Saturn
orig_func = (void*)0x06044ae0;
*(u32*)(0x0604ed28) = (u32)cdp_hook;
}
}else{
printk("Unkonw BIOS ver!\n");
@ -56,46 +142,73 @@ static void hook_getkey(void)
static int cdp_boot(void)
{
int pad = (sk0)? sk0 : sk1;
printk("cdp_boot! PAD=%04x\n", pad);
printk("\ncdp_boot! PAD=%04x\n", pad);
hook_getkey();
force_no_bup = 0;
if(pad & PAD_START){
void (*go)(void) = (void*)(0x02000f00);
go();
}else if(pad & PAD_C){
}
if(pad & PAD_C){
// SAROO启动但用系统存档
force_no_bup = 1;
bios_cd_cmd(0);
bios_cd_cmd(disc_type|0x80);
}else if(pad & PAD_A){
// SAROO启动
bios_cd_cmd(0);
bios_cd_cmd(disc_type);
}
return 0;
}
static int cdp_read_ip(void)
{
if(debug_flag&1)
sci_init();
int ip_size = my_bios_loadcd_boot(0, 0x1876);
if((ip_size==-8)||(ip_size==-4)){
ip_size=0x0;
}
printk("\ncdp_read_ip: %d\n", ip_size);
hook_getkey();
return ip_size;
printk("\ncdp_read_ip!\n");
if(disc_type==0){
// SAROO ISO
int (*go)(void) = (void*)0x1874;
int status = go();
if((status==-8)||(status==-4)){
status = 0;
}
return status;
}else{
// 光盘
return cdp_auth();
}
}
static int cdp_init(void)
{
printk("\ncdp_init! HIRQ=%04x STAT=%04x\n", HIRQ, CR1);
if(disc_type==0){
int (*go)() = (void*)0x1904;
return go();
}
if(HIRQ&HIRQ_DCHG){
ipstat = 0;
}else{
ipstat = 12;
}
return 0;
}
/**********************************************************/
static void (*orig_0344)(int, int);
static void my_0344(int and, int or)
@ -173,28 +286,33 @@ void my_cdplayer(void)
*(u32*)(0x06000358) = (u32)bup_init;
if(*(u32*)(0x06001340)==0x18a8){
// 1.00
bios_ver = 0;
cdp_boot_game = (void*)0x18a8;
*(u32*)(0x06001340) = (u32)cdp_boot;
*(u32*)(0x06001344) = (u32)cdp_read_ip;
}else if(*(u32*)(0x0600134c)==0x18a8){
// 1.01 1.02
bios_ver = 1;
cdp_boot_game = (void*)0x18a8;
*(u32*)(0x0600134c) = (u32)cdp_boot;
*(u32*)(0x06001350) = (u32)cdp_read_ip;
}else if(*(u32*)(0x060013d8)==0x19b8){
// 1.03
bios_ver = 2;
cdp_boot_game = (void*)0x19b8;
*(u32*)(0x060013d8) = (u32)cdp_boot;
*(u32*)(0x060013dc) = (u32)cdp_read_ip;
}
if(use_sys_load==0){
if(*(u32*)(0x06001340)==0x18a8){
// 1.00
bios_ver = 0;
cdp_boot_game = (void*)0x18a8;
*(u32*)(0x06001340) = (u32)cdp_boot;
*(u32*)(0x06001344) = (u32)cdp_read_ip;
*(u32*)(0x06001348) = (u32)cdp_init;
}else if(*(u32*)(0x0600134c)==0x18a8){
// 1.01 1.02
bios_ver = 1;
cdp_boot_game = (void*)0x18a8;
*(u32*)(0x0600134c) = (u32)cdp_boot;
*(u32*)(0x06001350) = (u32)cdp_read_ip;
*(u32*)(0x06001354) = (u32)cdp_init;
}else if(*(u32*)(0x060013d8)==0x19b8){
// 1.03
bios_ver = 2;
cdp_boot_game = (void*)0x19b8;
*(u32*)(0x060013d8) = (u32)cdp_boot;
*(u32*)(0x060013dc) = (u32)cdp_read_ip;
*(u32*)(0x060013e0) = (u32)cdp_init;
}
orig_0344 = (void*)*(u32*)(0x06000344);
*(u32*)(0x06000344) = (u32)my_0344;
orig_0344 = (void*)*(u32*)(0x06000344);
*(u32*)(0x06000344) = (u32)my_0344;
}
*(u32*)(0x06000234) = 0x02ac;
*(u32*)(0x06000238) = 0x02bc;
@ -207,6 +325,9 @@ void my_cdplayer(void)
}
/**********************************************************/
int my_bios_loadcd_init(void)
{
printk("\nmy_bios_loadcd_init!\n");
@ -247,7 +368,8 @@ int my_bios_loadcd_read(void)
tm -= 1;
}
if(tm==0){
printk(" PLAY timeout!\n");
printk(" PLAY timeout! HIRQ=%04x CR1=%04x\n", HIRQ, CR1);
cdc_dump(10000000);
return -1;
}
@ -255,7 +377,17 @@ int my_bios_loadcd_read(void)
cdc_trans_data(sbuf, 2048*16);
cdc_end_trans(&status);
*(u16*)(0x060003a0) = 1;
if(strncmp("SEGA SEGASATURN ", (char*)0x06002000, 16)){
printk("Not a gamedisc!\n");
return -2;
}
if(bios_type<=BIOS_100V){
// 1.00j and V-Saturn 1.00
*(u16*)(0x06000380) = 1;
}else{
*(u16*)(0x060003a0) = 1;
}
memcpy(ipstr, (u8*)0x06002020, 16);
ipstr[16] = 0;
@ -300,19 +432,23 @@ static void my_06b0(void)
static void read_1st(void)
{
printk("Read main ...\n");
int retv;
retv = *(u32*)(0x06000284);
void (*go)(void) = (void(*)(void))retv;
void (*go)(void) = (void*) *(u32*)(0x06000284);
go();
patch_game((char*)0x06002020);
if(force_no_bup==0 && need_bup){
*(u32*)(0x06000358) = (u32)bup_init;
}
if(need_bup){
*(u32*)(0x06000358) = (u32)bup_init;
*(u32*)(0x0600026c) = (u32)my_cdplayer;
}
force_no_bup = 0;
// 有些游戏没有正确初始化VDP1。这里特殊处理一下。
memset((u8*)0x25c00200, 0x00, 0x80000-0x200);
for(int i=0; i<0x80000; i+=0x20){
*(u16*)(0x25c00000+i) = 0x8000;
}
*(u16*)(0x25c7fffe) = 0xffff;
// 0x06000320: 0x060006b0 bios_set_clock_speed
memcpy((u8*)0x060006b8, code_06b8, sizeof(code_06b8));
@ -332,52 +468,55 @@ static void read_1st(void)
}
static int my_bios_loadcd_boot(int r4, int r5)
{
__asm volatile ( "sts.l pr, @-r15" :: );
__asm volatile ( "jmp @%0":: "r" (r5) );
__asm volatile ( "mov r4, r0" :: );
__asm volatile ( "nop" :: );
return 0;
}
int bios_cd_cmd(int type)
{
int retv, ip_size;
my_bios_loadcd_init();
use_sys_bup = (type&0x80)>>7;
use_sys_load = 0;
type &= 0x7f;
disc_type = type;
#if 1
my_bios_loadcd_boot(0, 0x1904);
printk("bios_cd_cmd: type=%02x\n", type);
while(1){
ip_size = bios_loadcd_read();
if(ip_size==0x8000)
break;
#if 0
if(type!=2){
// 0:ISO, 4:光盘
bios_loadcd_init();
while(1){
ip_size = bios_loadcd_read();
if(ip_size==0x8000)
break;
}
char ipstr[64];
memcpy(ipstr, (u8*)0x06002020, 16);
ipstr[16] = 0;
printk("\nLoad game: %s\n", ipstr);
memcpy(ipstr, (u8*)0x06002060, 32);
ipstr[32] = 0;
printk(" %s\n\n", ipstr);
}else
#endif
{
// 2: 刻录游戏盘
my_bios_loadcd_init();
retv = my_bios_loadcd_read();
if(retv<0){
if(retv==-2){
use_sys_load = 1;
my_cdplayer();
}
return retv;
}
// emulate bios_loadcd_boot
*(u32*)(0x06000290) = 3;
ip_size = bios_loadcd_read();//1912读取ip文件
}
char ipstr[64];
memcpy(ipstr, (u8*)0x06002020, 16);
ipstr[16] = 0;
printk("\nLoad game: %s\n", ipstr);
memcpy(ipstr, (u8*)0x06002060, 32);
ipstr[32] = 0;
printk(" %s\n\n", ipstr);
#else
retv = my_bios_loadcd_read();
if(retv)
return retv;
// emulate bios_loadcd_boot
*(u32*)(0x06000290) = 3;
ip_size = bios_loadcd_read();//1912读取ip文件
#endif
if(type>0){
if(type>0 && use_sys_bup==0){
// 光盘游戏。需要通知MCU加载SAVE。
memcpy((void*)(TMPBUFF_ADDR+0x10), (u8*)0x06002020, 16);
*(u8*)(TMPBUFF_ADDR+0x20) = 0;
@ -387,15 +526,23 @@ int bios_cd_cmd(int type)
while(SS_CMD);
}
*(u32*)(0x06002270) = (u32)read_1st;
// 模拟执行1A3c()
// 跳过各种验证
memcpy((u8*)0x060002a0, (u8*)0x060020e0, 32);
memcpy((u8*)0x06000c00, (u8*)0x06002000, 256);
*(u32*)(0x06000254) = 0x6002100;
// 模拟执行18fe()
cdc_change_dir(0, 0xffffff);
cdc_read_file(0, 2, 0);
*(u32*)(0x06002270) = (u32)read_1st;
*(u32*)(0x02000f04) = (u32)cdc_read_sector;
*(u16*)(0x0600220c) = 9;
retv = my_bios_loadcd_boot(ip_size, 0x18be);//跳到18be
if((retv==-8)||(retv==-4)){
*(u32*)(0x06000254) = 0x6002100;
retv = my_bios_loadcd_boot(0, 0x18c6);
}
int (*go)(void) = (void*)0x18d2;
retv = go();
printk("bios_loadcd_boot retv=%d\n", retv);
return retv;

View file

@ -59,6 +59,7 @@ void CHEAT_patch(void)
/**********************************************************/
// KAITEI_DAISENSOU (Japan) 海底大战争日版 第一关后半部分会有音乐丢失情况
void KAITEI_DAISENSOU_handle1(void)
{
cdc_read_sector(2462+150, 0x54f00, (void*)0x22400000);
@ -80,50 +81,64 @@ void KAITEI_DAISENSOU_patch(void)
/**********************************************************/
// Dungeons & Dragons Collection (Japan) (Disc 2) 龙与地下城2
void DND2_patch(void)
{
*(u32*)(0x06015228) = 0x34403440;
//*(u32*)(0x06015228) = 0x34403440;
*(u16*)(0x060151A6) = 0x09;
*(u16*)(0x060151AE) = 0x09;
}
/**********************************************************/
// NOEL3 (Japan)
void NOEL3_patch(void)
{
*(u32*)(0x0603525C) = 0x34403440;
//*(u32*)(0x0603525C) = 0x34403440;
*(u16*)(0x06035104) = 0x09;
}
/**********************************************************/
// FRIENDS (Japan)
void FRIENDS_patch(void)
{
*(u32*)(0x06042928) = 0x34403440;
*(u32*)(0x060429B4) = 0x34403440;
//*(u32*)(0x06042928) = 0x34403440;
//*(u32*)(0x060429B4) = 0x34403440;
*(u16*)(0x060428E8) = 0x09;
*(u16*)(0x0604298A) = 0x09;
}
/**********************************************************/
// Astra Superstars (Japan)
void ASTRA_SUPERSTARS_patch(void)
{
*(u32*)(0x060289E4) = 0x34403440;
//*(u32*)(0x060289E4) = 0x34403440;
*(u16*)(0x06028974) = 0x09;
}
/**********************************************************/
// Magical Night Dreams - Cotton 1 (Japan)棉花小魔女1
void cotton1_patch(void)
{
*(u32*)(0x06018DA8) = 0x34403440;
//*(u32*)(0x06018DA8) = 0x34403440;
*(u16*)(0x06018D80) = 0x09;
}
/**********************************************************/
// Magical Night Dreams - Cotton 2 (Japan)棉花小魔女2
void cotton2_patch(void)
{
*(u32*)(0x060041BC) = 0x34403440;
//*(u32*)(0x060041BC) = 0x34403440;
*(u16*)(0x06004194) = 0x09;
}
@ -131,40 +146,53 @@ void cotton2_patch(void)
// Pocket Fighter (Japan) 口袋战士
void POCKET_FIGHTER_patch(void)
{
*(u32*)(0x06014080) = 0x34403440;
//*(u32*)(0x06014080) = 0x34403440;
*(u32*)(0x06013F48) = 0xd44ae001;
*(u32*)(0x06013F4c) = 0x2400e05c;
*(u32*)(0x06013F50) = 0x000b8041;
//*(u8*)(0x06037C2A) = 0x11;//錦攣역庫稜틉굳댄轎돨꺄렴??
*(u16*)(0x0602DD68) = 0x09;
}
/**********************************************************/
// Street Fighter Zero 3 (Japan) 街霸ZERO3
void SF_ZERO3_patch(void)
{
*(u32*)(0x0602B8AC) = 0x34403440;
//*(u32*)(0x0602B8AC) = 0x34403440;
*(u16*)(0x0602B7FA) = 0x09;
}
/**********************************************************/
// Metal_Slug 合金弹头
void Metal_Slug_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x06079E18) = 0x34403440;
//*(u32*)(0x06079E18) = 0x34403440;
*(u16*)(0x06079DEC) = 0x09;
//*(u16*)(0x06079DF2) = 0x09;
}
/*********************************************************/
//Metal_Slug A 북쏜뎐庫1.005경
// Metal_Slug A 북쏜뎐庫1.005경
void Metal_Slug_A_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x06079FBC) = 0x34403440;
//*(u32*)(0x06079FBC) = 0x34403440;
*(u16*)(0x06079F90) = 0x09;
//*(u16*)(0x06079F96) = 0x09;
}
/*********************************************************/
// ULTRAMAN
// 2MB ROM cart
void jump_06b0(void)
{
void (*go)(void) = (void*)(0x04c8);
@ -218,15 +246,16 @@ void ULTRAMAN_patch(void)
/*********************************************************/
// KOF95
// 2MB ROM cart
void kof95_handle(void)
{
if(*(u32*)(0x6002234)== 0x14401FF0) *(u32*)(0x6002234) = 0x34403440;
if(*(u32*)(0x600230c)== 0x14401FF0) *(u32*)(0x600230c) = 0x34403440;
if(*(u32*)(0x6002300)== 0x1FF01FF0) *(u32*)(0x6002300) = 0x34403440;
*(u16*)(0x60020c2) = 0x0009;
*(u16*)(0x600217E) = 0x0009;
*(u16*)(0x6002180) = 0x0009;
read_file("/SAROO/ISO/KOF95.BIN", 0, 0x200000, (void*)0x22400000);
card_init();
void (*go)(int);
go = (void*)0x200000;
go(0x6002048);
@ -237,37 +266,45 @@ void kof95_patch(void)
{
need_bup = 0;
if(*(u32*)(0x6002e28)==0x0607CD80)
*(u32*)(0x607CDC4) = (u32)kof95_handle;
if(*(u32*)(0x6002e28)==0x0607CD80){
if(*(u32*)(0x607CDC4) == 0x6002048)
*(u32*)(0x607CDC4) = (u32)kof95_handle;
else if(*(u32*)(0x607CDC8) == 0x6002048)
*(u32*)(0x607CDC8) = (u32)kof95_handle;
}
}
/**********************************************************/
// KOF96
// 1MB RAM cart only
void kof96_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x06058248) = 0x34403440;
//*(u32*)(0x06058248) = 0x34403440;
*(u16*)(0x0605821C) = 0x09;
}
/**********************************************************/
// KOF97
void kof97_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x06066FC0) = 0x34403440;
*(u16*)(0x06066F80) = 0x0009;//34403440
}
/**********************************************************/
// Samurai Spirits - Amakusa Kourin 侍魂4
// 1MB RAM cart only
void smrsp4_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x6067E60) = 0x34403440;
//*(u32*)(0x6067E60) = 0x34403440;
*(u16*)(0x06067E34) = 0x0009;
}
@ -275,11 +312,14 @@ void smrsp4_patch(void)
// Samurai Spirits - Zankuro Musouken 侍魂3
// 0x0600d1d0: 23301ff0
// 0x0605ad90: 23301ff0
void smrsp3_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)0x0600d1d0 = 0x34403440;
*(u32*)0x0605ad90 = 0x34403440;
*(u16*)(0x0600D198) = 0x0009;
*(u16*)(0x0605AD36) = 0x0009;
//*(u32*)0x0600d1d0 = 0x34403440;
//*(u32*)0x0605ad90 = 0x34403440;
}
@ -287,21 +327,26 @@ void smrsp3_patch(void)
// Real Bout Garou Densetsu (Japan) (2M) RB饿狼传说
// 0x0602F6FC: 23301ff0
// 0x0607C36C: 23301ff0
void REAL_BOUT_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)0x0602F6FC = 0x34403440;
*(u32*)0x0607C36C = 0x34403440;
*(u16*)(0x0602F5EC) = 0x0009;
*(u16*)(0x0607C340) = 0x0009;
//*(u32*)0x0602F6FC = 0x34403440;
//*(u32*)0x0607C36C = 0x34403440;
}
/**********************************************************/
// Real Bout Garou Densetsu Special (Japan) (Rev A) RB饿狼传说SP V2
// 0x060913C4: 23301ff0
void REAL_BOUT_SP_v2_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)0x060913C4 = 0x34403440;
//*(u32*)0x060913C4 = 0x34403440;
*(u16*)(0x06091398) = 0x0009;
}
@ -309,10 +354,12 @@ void REAL_BOUT_SP_v2_patch(void)
// Real Bout Garou Densetsu Special (Japan) v1 RB饿狼传说SP V1
// 0x060913C4: 23301ff0
// 0x06091230: 23301ff0
void REAL_BOUT_SP_v1_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)0x06091230 = 0x34403440;
*(u16*)(0x06091204) = 0x0009;
//*(u32*)0x06091230 = 0x34403440;
}
@ -320,18 +367,23 @@ void REAL_BOUT_SP_v1_patch(void)
// SRMP7
// 0x06011204: mov.l #0x23301ff0, r3
// need change to 0x34403440
void srmp7_patch(void)
{
*(u32*)(0x0601121C) = 0x34403440;
//*(u32*)(0x0601121C) = 0x34403440;
*(u16*)(0x06011208) = 0x0009;
}
/**********************************************************/
// Gouketsuji Ichizoku 3 - Groove on Fight (Japan)豪血寺一族3
void GROOVE_ON_FIGHT_handle(void)
{
*(u32*)0x06099ABC=0x34403440;
*(u32*)0x060083B0=0x34403440;
//*(u32*)0x06099ABC=0x34403440;
//*(u32*)0x060083B0=0x34403440;
*(u16*)(0x6008338) = 0x0009;
*(u16*)(0x6099A84) = 0x0009;
*(u32*)0x00280008=0x06004000;
__asm volatile("jmp @%0"::"r"(0x06004000));
__asm volatile( "nop" :: );
@ -339,17 +391,21 @@ void GROOVE_ON_FIGHT_handle(void)
void GROOVE_ON_FIGHT_patch(void)
{
*(u32*)(0x200AA4) = 0x34403440;
*(u32*)(0x202EF0) = 0x34403440;
//*(u32*)(0x200AA4) = 0x34403440;
//*(u32*)(0x202EF0) = 0x34403440;
*(u16*)(0x200A44) = 0x0009;
*(u16*)(0x202EB8) = 0x0009;
*(u32*)(0x200460) = (u32)GROOVE_ON_FIGHT_handle;
}
/**********************************************************/
// Vampire Savior (Japan) 恶魔战士3 救世主
void VAMPIRE_SAVIOR_handle(void)
{
*(u32*)0x06014A64=0x34403440;
//*(u32*)0x06014A64=0x34403440;
*(u16*)(0x6014A52) = 0x0009;
__asm volatile("jmp @%0"::"r"(0x600D000));
__asm volatile ( "nop" :: );
}
@ -365,32 +421,53 @@ void VAMPIRE_SAVIOR_patch(void)
/**********************************************************/
// XMarvel Super Heroes (Japan)
void MARVEL_SUPER_handle(void)
{
void (*go)(void) = (void(*)(void))0x60D0FF4;
go();
*(u32*)0x0600B0FC = 0x34403440;
*(u32*)0x0600B2D8 = 0x34403440;
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
if((REG32(0x600B0FC) == 0x23301FF0) && (REG32(0x600B2D8) == 0x23301FF0)){
//휑경 킹경 쳄경뒈囹宮谿
REG16(0x600B0AC) = 0x0009;
REG16(0x600B1D4) = 0x0009;
}else if((REG32(0x6005F5C) == 0x23301FF0)&&(REG32(0x6005D8C) == 0x23301FF0)){
//휑경DEMO
REG16(0x6005D3C) = 0x0009;
REG16(0x6005E6A) = 0x0009;
}
}
void MARVEL_SUPER_patch(void)
{
*(u32*)(0x060D13F8) = (u32)MARVEL_SUPER_handle;
if(REG32(0x60D13F8) == 0X60D0FF4){
//휑경뵨쳄경
REG32(0x60D13F8)=(u32)MARVEL_SUPER_handle;
}else if(REG32(0x60D1424) == 0X60D0FF4){
//휑경DEMO
REG32(0x60D1424)=(u32)MARVEL_SUPER_handle;
}else if(REG32(0x60D15AC) == 0X60D0FF4){
//킹경
REG32(0x60D15AC)=(u32)MARVEL_SUPER_handle;
}
}
/**********************************************************/
// X-Men vs. Street Fighter (Japan) (3M)
void xmvsf_handle2(void)
{
*(u32*)(0x06014158) = 0x34403440;
//*(u32*)(0x06014158) = 0x34403440;
*(u16*)(0x0601409C) = 0x0009;
__asm volatile("jmp @%0"::"r"(0x6014000));
__asm volatile ( "nop" :: );
}
void xmvsf_handle1(void)
{
*(u16*)(0x60228E0) = 0xe000;
*(u16*)(0x60228f4) = 0xe000;
*(u8*)0x060801FE = 0x5c;
@ -410,6 +487,7 @@ void xmvsf_patch(void)
/**********************************************************/
// Marvel Super Heroes vs. Street Fighter (Japan)
void mshvssf_handle1(void)
{
if(*(u16*)(0x600286e)== 0x2012)
@ -430,10 +508,11 @@ void mshvssf_patch(void)
/**********************************************************/
// WAKUWAKU7 火热火热7
void WAKU7_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)(0x0601C19C) = 0x34403440;
*(u16*)(0x0601C164) = 0x9;
*(u16*)(0x0601C16C) = 0x9;
*(u8*) (0x0601244d) = 0xa;
@ -452,13 +531,18 @@ void WAKU7_patch(void)
/**********************************************************/
// FIGHTERS_HISTORY 斗士的历史
void FIGHTERS_HISTORY_patch(void)
{
ssctrl_set(MASK_EXMEM, CS0_RAM1M);
*(u32*)0x060500C8 = 0x34403440;
*(u32*)0x06057000 = 0x34403440;
*(u32*)0x0605707C = 0x34403440;
*(u32*)0x060570E0 = 0x34403440;
*(u16*)(0x0605002E) = 0x9;
*(u16*)(0x06056FEC) = 0x9;
*(u16*)(0x06057028) = 0x9;
*(u16*)(0x060570BA) = 0x9;
//*(u32*)0x060500C8 = 0x34403440;
//*(u32*)0x06057000 = 0x34403440;
//*(u32*)0x0605707C = 0x34403440;
//*(u32*)0x060570E0 = 0x34403440;
}
@ -467,7 +551,8 @@ void FIGHTERS_HISTORY_patch(void)
void FINAL_FIGHT_REVENGE_patch(void)
{
*(u32*)(0x06011A6C) = 0x34403440;
//*(u32*)(0x06011A6C) = 0x34403440;
*(u16*)(0x0601199C) = 0x9;
}
@ -567,16 +652,12 @@ void Terra_Cresta_3D_patch(void)
/**********************************************************/
// 빪델질瓜 밑균속醵엥
// 빪델질瓜
// 踏狗넋埼逃癎뺄쉥0x25E7FFFF畇냥0x25E7FFF죄닒VRAM돕CS0죄。
void Die_Hard_Trilogy_patch(void)
{
if(*(u8*)(0x060523B4)==0x60)
*(u16*)(0x060523BA) = 0x9; // 휑경
else if(*(u8*)(0x06050CA8)==0x60)
*(u16*)(0x06050CAE) = 0x9; // 쳄경
else if(*(u8*)(0x060523B0)==0x60)
*(u16*)(0x060523B6) = 0x9; // 킹경
*(u8*)(0x025E7FFF) = 0xff;
}
@ -616,11 +697,12 @@ void Dragons_Dream_patch(void)
void Hebereke_Popoitto_patch(void)
{
if(*(u8*)(0x0601D379)==0x01)
if(*(u8*)(0x0601D379)==0x01){
*(u8*)(0x0601D379) = 0x56; // (Japan)
else if(*(u8*)(0x0601D399)==0x01)
*(u8*)(0x0601D2F5) = 0x56;
}else if(*(u8*)(0x0601D399)==0x01){
*(u8*)(0x0601D399) = 0x78; // (Europe)
}
}
@ -642,9 +724,10 @@ void Hissatsu_Pachinko_Collection_patch(void)
void Heart_of_Darkness_patch(void)
{
*(u16*)(0x060106C4) = 9;
*(u8*) (0x060108C0) = 2;
*(u8*) (0x060108C1) = 0x40;
if(*(u32*)(0x060108c0)==0x04000000){
*(u16*)(0x060108C0) = 0x0240;
*(u16*)(0x060106C4) = 0x0009;
}
}
@ -653,13 +736,21 @@ void Heart_of_Darkness_patch(void)
void VANDAL_HEARTS_CN_patch(void)
{
if(REG16(0x06002F70)==0x4C2B){ // 1.0 攣駕경
REG16(0x06002F70)=0xaf48;
int addres=0;
if(REG16(0x06002F70)==0x4C2B) // B2
addres=0x48;
else if(REG16(0x06002F5e)==0x4C2B) // B1
addres=0x51;
if(addres){
REG8(0x06002F5e) =0xaf;
REG8(0x06002F5f) =addres;
REG32(0x06002E04)=0xE00961C3;
REG32(0x06002E08)=0x71547170;
REG32(0x06002E0C)=0x4C2B2101;
}
}
}
/**********************************************************/
@ -702,6 +793,128 @@ void Fenrir_patch(void)
}
/**********************************************************/
void Pia_Carrot_e_Youkoso_2_handle2(void)
{
if((REG32(0x604677C)==0x23301FF0) && (REG16(0x604673C)==0x2122))
REG16(0x604673C) = 0x9;
if((REG32(0x6046808)==0x23301FF0) && (REG16(0x60467DE)==0x2122))
REG16(0x60467DE)=0x9;
if((REG32(0x6046784)==0x60468F8) && (REG16(0x0604674C)==0x490b))
REG16(0x0604674C)=0x9;
void (*go)(void) = (void*)0X6010000;
go();
}
void Pia_Carrot_e_Youkoso_2_handle1(void)
{
if(REG32(0x2100C0)==0x6010000)
REG32(0x2100C0)= (u32)Pia_Carrot_e_Youkoso_2_handle2;
void (*go)(void) = (void*)0x6021FE4;
go();
}
void Pia_Carrot_e_Youkoso_2_patch(void)
{
if((REG32(0x601068C)==0x210000) && (REG32(0x60106B0)==0x6021FE4))
REG32(0x60106B0)= (u32)Pia_Carrot_e_Youkoso_2_handle1;
}
/**********************************************************/
// Ultimate Mortal Kombat 3 쳄경 킹경 킹경錦攣경
void Ultimate_Mortal_Kombat_3_patch(void)
{
int r0 = 0x0601875A;
if(REG16(r0)==0x480b)//쳄경 킹경
REG16(r0)= 0x09;
if(REG16(r0+0x10)==0x480b)//킹경錦攣경
REG16(r0+0x10)= 0x09;
if(REG16(r0+0x54)==0x480b)//쳄경 킹경
REG16(r0+0x54)= 0x09;
if(REG16(r0+0x64)==0x480b)//킹경錦攣경
REG16(r0+0x64)= 0x09;
}
/**********************************************************/
// Batman_Forever_The_Arcade_Game 쳄경 킹경 킹경錦攣경
void Batman_Forever_The_Arcade_Game_handle1(void)
{
int r0=0x06023E44;
if(REG32(r0)==0xD439490B){
//휑경 쳄경 킹경宮谿
REG32(r0) = 0xD23A6122;
REG32(r0+4) = 0x21188BFC;
REG32(r0+8) = 0xD437490B;
REG32(r0+12)= 0x6583EB00;
}
__asm volatile("jmp @%0"::"r"(0x600d000));
__asm volatile ("nop" :: );
}
void Batman_Forever_The_Arcade_Game_patch(void)
{
if(REG32(0x060043C4)==0x600AF9C){
//휑경 쳄경 킹경 寮넋埼宮谿
REG32(0x060043C4) = (u32)Batman_Forever_The_Arcade_Game_handle1;
}
}
/**********************************************************/
//Game no Tatsujin 2 (Japan)껸땀
void Game_no_Tatsujin2_patch(void)
{
if(*(u32*)(0x06011024)==0x880189ED){
*(u16*)(0x06011026) = 0x09;
}
}
/**********************************************************/
void MANX_TT_SUPER_BIKE_patch(void)
{
if(*(u8*)(0x60219B1)==0x01){
//휑경뵨킹경宮谿
*(u8*)(0x60219B3)= 0x03;
*(u8*)(0x60219E7)= 0x03;
*(u8*)(0x602037D)= 0x43;
*(u8*)(0x60203FD)= 0x43;
*(u8*)(0x60204D9)= 0x43;
*(u8*)(0x6020619)= 0x13;
}else if(*(u8*)(0x6021A11)==0x01){
//쳄경
*(u8*)(0x6021A13)= 0x03;
*(u8*)(0x6021A47)= 0x03;
*(u8*)(0x60203DD)= 0x43;
*(u8*)(0x602045D)= 0x43;
*(u8*)(0x6020539)= 0x43;
*(u8*)(0x6020679)= 0x13;
}
}
/**********************************************************/
int skip_patch = 0;
@ -749,7 +962,10 @@ GAME_DB game_dbs[] = {
{"GS-9107", "FIGHTERS_HISTORY", FIGHTERS_HISTORY_patch},
{"T-1248G", "FINAL_FIGHT_REVENGE",FINAL_FIGHT_REVENGE_patch},
{"T-1226G", "XMEN_VS_SF", xmvsf_patch},
{"T-1215G", "MARVEL_SUPER", MARVEL_SUPER_patch},
{"T-1215G", "MARVEL_SUPER", MARVEL_SUPER_patch}, //휑경
{"T-1214H", "MARVEL_SUPER", MARVEL_SUPER_patch}, //쳄경
{"6106664", "MARVEL_SUPER", MARVEL_SUPER_patch}, //휑경demo
{"T-7032H", "MARVEL_SUPER", MARVEL_SUPER_patch}, //킹경
{"T-1238G V1.000", "MSH_VS_SF", mshvssf_patch},
{"T-1513G", "Amagi_Shien", Amagi_Shien_patch},
@ -784,14 +1000,24 @@ GAME_DB game_dbs[] = {
{"T-000001 V0.2.0", "RMENU2", RMENU2_patch},
{"CD0000001 V1.000", "Fenrir", Fenrir_patch},
{"GS-9102 V1.001", "ManX_TT_Super_Bike", MANX_TT_SUPER_BIKE_patch},
{"MK-81210 V1.001", "ManX_TT_Super_Bike", MANX_TT_SUPER_BIKE_patch},
{"MK-81210 V1.000", "ManX_TT_Super_Bike", MANX_TT_SUPER_BIKE_patch},
{"T-20114G", "PIA CARROT 2", Pia_Carrot_e_Youkoso_2_patch},
{"T-25403H", "u_m_k3", Ultimate_Mortal_Kombat_3_patch}, // 廬훙우댔3 킹경/錦攣경
{"T-9701H", "u_m_k3", Ultimate_Mortal_Kombat_3_patch}, // 廬훙우댔3 쳄경
{"T-8140H", "B_F_T", Batman_Forever_The_Arcade_Game_patch}, // 朕疾舅 쳄경 킹경/錦攣경
{"T-8118G", "B_F_T", Batman_Forever_The_Arcade_Game_patch}, // 朕疾舅 휑경
{"T-1509G", "G_N_T2", Game_no_Tatsujin2_patch}, //Game no Tatsujin 2 (Japan)
{NULL,},
};
// Marvel Super Heroes (Europe) T-7032H-50
// Pia Carrot e Youkoso!! 2 (Japan) T-20114G
//
//
void patch_game(char *id)
{

View file

@ -241,7 +241,7 @@ static void mbuf_mark(int id)
}
}
#ifdef BUP_CHECK
static int chksum(u8 *data, int size)
{
int sum = 0;
@ -254,6 +254,7 @@ static int chksum(u8 *data, int size)
return sum;
}
#endif
static int access_data(int block, u8 *data, int type)
{
@ -290,13 +291,17 @@ static int access_data(int block, u8 *data, int type)
if(type==0){ // read
memcpy(data, bp, asize);
//printk(" sum=%08x\n", chksum(data, asize));
#ifdef BUP_CHECK
printk(" sum=%08x\n", chksum(data, asize));
#endif
}else if(type==1){
if(memcmp(data, bp, asize)){
return BUP_NO_MATCH;
}
}else{ // write
//printk(" sum=%08x\n", chksum(data, asize));
#ifdef BUP_CHECK
printk(" sum=%08x\n", chksum(data, asize));
#endif
memcpy(bp, data, asize);
mbuf_mark(block);
}
@ -369,19 +374,19 @@ static int find_save(char *file_name, int offset, int *last)
/******************************************************************************/
int bup_sel_part(int dev, int num)
// 根据BIOS的BUP代码只有dev为2时才检测num。
int sro_bup_sel_part(int dev, int num)
{
printk("bup_sel_part(%d): %d\n", dev, num);
if(dev>1 || num)
if(dev>=2)
return BUP_NON;
return 0;
}
int bup_format(int dev)
int sro_bup_format(int dev)
{
printk("bup_format(%d)\n", dev);
@ -418,7 +423,7 @@ int bup_format(int dev)
}
int bup_stat(int dev, int dsize, BUPSTAT *stat)
int sro_bup_stat(int dev, int dsize, BUPSTAT *stat)
{
printk("bup_stat(%d): dsize=%d\n", dev, dsize);
@ -451,7 +456,7 @@ int bup_stat(int dev, int dsize, BUPSTAT *stat)
}
int bup_write(int dev, BUPDIR *dir, u8 *data, int mode)
int sro_bup_write(int dev, BUPDIR *dir, u8 *data, int mode)
{
int block_need, block, hdr, last, i;
u8 *bp;
@ -548,7 +553,7 @@ int bup_write(int dev, BUPDIR *dir, u8 *data, int mode)
}
int bup_read(int dev, char *file_name, u8 *data)
int sro_bup_read(int dev, char *file_name, u8 *data)
{
int block;
char nbuf[12];
@ -573,7 +578,7 @@ int bup_read(int dev, char *file_name, u8 *data)
}
int bup_delete(int dev, char *file_name)
int sro_bup_delete(int dev, char *file_name)
{
int block, last, has_data;
u8 *bp;
@ -649,7 +654,7 @@ int bup_delete(int dev, char *file_name)
}
int bup_dir(int dev, char *file_name, int tbsize, BUPDIR *dir)
int sro_bup_dir(int dev, char *file_name, int tbsize, BUPDIR *dir)
{
int block, fnum;
char nbuf[12];
@ -693,7 +698,7 @@ int bup_dir(int dev, char *file_name, int tbsize, BUPDIR *dir)
}
int bup_verify(int dev, char *file_name, u8 *data)
int sro_bup_verify(int dev, char *file_name, u8 *data)
{
int block;
char nbuf[12];
@ -718,7 +723,7 @@ int bup_verify(int dev, char *file_name, u8 *data)
static char mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
void bup_get_date(u32 date, BUPDATE *bdt)
void sro_bup_get_date(u32 date, BUPDATE *bdt)
{
int y, d, h, m;
printk("bup_get_date: %08x\n", date);
@ -758,7 +763,7 @@ void bup_get_date(u32 date, BUPDATE *bdt)
}
u32 bup_set_date(BUPDATE *bdt)
u32 sro_bup_set_date(BUPDATE *bdt)
{
u32 date;
int y, m ,rem;
@ -793,6 +798,124 @@ u32 bup_set_date(BUPDATE *bdt)
/******************************************************************************/
int use_sys_bup = 0;
int (*sys_bup_sel_part)(int dev, int num);
int (*sys_bup_format)(int dev);
int (*sys_bup_stat)(int dev, int dsize, BUPSTAT *stat);
int (*sys_bup_write)(int dev, BUPDIR *dir, u8 *data, int mode);
int (*sys_bup_read)(int dev, char *file_name, u8 *data);
int (*sys_bup_delete)(int dev, char *file_name);
int (*sys_bup_dir)(int dev, char *file_name, int tbsize, BUPDIR *dir);
int (*sys_bup_verify)(int dev, char *file_name, u8 *data);
void (*sys_bup_get_date)(u32 date, BUPDATE *bdt);
u32 (*sys_bup_set_date)(BUPDATE *bdt);
int bup_sel_part(int dev, int num)
{
if(use_sys_bup && dev==0){
return sys_bup_sel_part(dev, num);
}else{
return sro_bup_sel_part(dev, num);
}
}
int bup_format(int dev)
{
if(use_sys_bup && dev==0){
return sys_bup_format(dev);
}else{
return sro_bup_format(dev);
}
}
int bup_stat(int dev, int dsize, BUPSTAT *stat)
{
if(use_sys_bup && dev==0){
return sys_bup_stat(dev, dsize, stat);
}else{
return sro_bup_stat(dev, dsize, stat);
}
}
int bup_write(int dev, BUPDIR *dir, u8 *data, int mode)
{
if(use_sys_bup && dev==0){
return sys_bup_write(dev, dir, data, mode);
}else{
return sro_bup_write(dev, dir, data, mode);
}
}
int bup_read(int dev, char *file_name, u8 *data)
{
if(use_sys_bup && dev==0){
return sys_bup_read(dev, file_name, data);
}else{
return sro_bup_read(dev, file_name, data);
}
}
int bup_delete(int dev, char *file_name)
{
if(use_sys_bup && dev==0){
return sys_bup_delete(dev, file_name);
}else{
return sro_bup_delete(dev, file_name);
}
}
int bup_dir(int dev, char *file_name, int tbsize, BUPDIR *dir)
{
if(use_sys_bup && dev==0){
return sys_bup_dir(dev, file_name, tbsize, dir);
}else{
return sro_bup_dir(dev, file_name, tbsize, dir);
}
}
int bup_verify(int dev, char *file_name, u8 *data)
{
if(use_sys_bup && dev==0){
return sys_bup_verify(dev, file_name, data);
}else{
return sro_bup_verify(dev, file_name, data);
}
}
void bup_get_date(u32 date, BUPDATE *bdt)
{
if(use_sys_bup){
return sys_bup_get_date(date, bdt);
}else{
return sro_bup_get_date(date, bdt);
}
}
u32 bup_set_date(BUPDATE *bdt)
{
if(use_sys_bup){
return sys_bup_set_date(bdt);
}else{
return sro_bup_set_date(bdt);
}
}
/******************************************************************************/
void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg_ptr)
{
BUPCFG *cfg = (BUPCFG*)cfg_ptr;
@ -802,12 +925,28 @@ void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg_ptr)
printk("bup_init: lib=%08x work=%08x\n", lib_addr, work_addr);
//memset(lib_addr, 0, 16384);
//memset(work_addr, 0, 8192);
if(use_sys_bup){
printk("sys_bup_init ... %08x\n", sys_bup_init);
sys_bup_init(lib_addr, work_addr, cfg_ptr);
printk("done.\n");
*(u32*)(BUP_WORK_ADDR) = (u32)work_addr;
sys_bup_sel_part = (void*)*(u32*)(work_addr+0x04);
sys_bup_format = (void*)*(u32*)(work_addr+0x08);
sys_bup_stat = (void*)*(u32*)(work_addr+0x0c);
sys_bup_write = (void*)*(u32*)(work_addr+0x10);
sys_bup_read = (void*)*(u32*)(work_addr+0x14);
sys_bup_delete = (void*)*(u32*)(work_addr+0x18);
sys_bup_dir = (void*)*(u32*)(work_addr+0x1c);
sys_bup_verify = (void*)*(u32*)(work_addr+0x20);
sys_bup_get_date = (void*)*(u32*)(work_addr+0x24);
sys_bup_set_date = (void*)*(u32*)(work_addr+0x28);
}else{
*(u32*)(BUP_WORK_ADDR) = (u32)work_addr;
*(u32*)(work_addr+0x00) = (u32)lib_addr;
cfg[0].unit_id = 1;
cfg[0].partition = 1;
}
*(u32*)(work_addr+0x00) = (u32)lib_addr;
*(u32*)(work_addr+0x04) = (u32)bup_sel_part;
*(u32*)(work_addr+0x08) = (u32)bup_format;
*(u32*)(work_addr+0x0c) = (u32)bup_stat;
@ -819,17 +958,17 @@ void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg_ptr)
*(u32*)(work_addr+0x24) = (u32)bup_get_date;
*(u32*)(work_addr+0x28) = (u32)bup_set_date;
cfg[0].unit_id = 1;
cfg[0].partition = 1;
cfg[1].unit_id = 2;
cfg[1].partition = 1;
cfg[2].unit_id = 0;
cfg[2].partition = 0;
// Check "SaroSave"
if(BUPMEM->magic0!=0x5361726f || BUPMEM->magic1!=0x53617665){
printk(" empty bup memory, need format.\n");
bup_format(0);
if(use_sys_bup==0){
// Check "SaroSave"
if(BUPMEM->magic0!=0x5361726f || BUPMEM->magic1!=0x53617665){
printk(" empty bup memory, need format.\n");
bup_format(0);
}
}
// Check "SaroMems"

View file

@ -261,7 +261,55 @@ static char *lang_it[LANG_STR_NR] = {
"Seleziona categoria di gioco",
};
#if 0
static char *lang_pl[LANG_STR_NR] = {
"Wybierz grę(%d/%d)",
"Wybierz plik(%d/%d)",
"Uruchamianie gry ......",
"Błąd uruchamiania gry! %d",
"Wczytywanie pliku ......",
"Błąd wczytywania pliku! %d",
"Wybierz grę",
"Systemowy CDPlayer",
"Wczytaj dysk z grą",
"Powłoka debugująca po UART",
"Wczytaj dane binarne",
"Aktualizacja Firmware",
"Aktualizacja trwa... Nie wyłączaj konsoli!",
"Błąd aktualizacji!",
"Aktualizacja ukończona! Uruchom ponownie!",
"Menu rozruchowe SAROO",
"Sprawdzanie dysku ......",
"Nie znaleziono dysku!",
"Nie znaleziono płyty z grą!",
"Wybierz kategorię gry",
};
static char *lang_swe[LANG_STR_NR] = {
"Välj spel(%d/%d)",
"Välj fil(%d/%d)",
"Laddar spel ......",
"Gick inte att starta spelet! %d",
"Laddar fil ......",
"Gick inte att ladda fil! %d",
"Välj spel",
"System CD-spelare",
"Ladda spelskiva",
"Seriellt felsökningsshell",
"Ladda binär",
"Uppdatera programvaran",
"Uppdaterar... Stäng inte av maskinen.",
"Uppdatering misslyckades!",
"Uppdatering klar! Var god starta om maskinen.",
"SAROO Boot Menu",
"Kontrollerar skivan ......",
"Hittade ingen skiva!",
"Inte en giltig spel skiva!",
"Välj spelkategori",
};
static char *lang_el[LANG_STR_NR] = {
"Επίλεξε Παιχνίδι(%d/%d)",
"Επίλεξε Αρχείο(%d/%d)",
@ -308,7 +356,7 @@ static char *lang_ro[LANG_STR_NR] = {
"Nu s-a detectat un disc cu jocuri compatibil!",
"Selectați categoria de jocuri",
};
#endif
static char **lang_list[] = {
lang_zhcn,
@ -321,8 +369,10 @@ static char **lang_list[] = {
lang_de,
lang_es,
lang_it,
// lang_el,
// lang_ro, // TODO: Need new font
lang_pl,
lang_swe,
lang_el,
lang_ro,
};
static const int lang_nr = sizeof(lang_list)/4;

View file

@ -16,6 +16,7 @@
u32 mcu_ver;
u32 debug_flag;
int bios_type;
/**********************************************************/
@ -52,6 +53,7 @@ void LE32W(void *ptr, u32 val)
/**********************************************************/
static int pad_state;
int pad_read(void)
@ -66,6 +68,8 @@ int pad_read(void)
bits ^= 0xfFF8;
#else
if(pad_state==0){
if((TVSTAT&0x0008)==0)
return -1;
while(SF&0x01);
SF = 0x01;
IREG0 = 0x00;
@ -74,14 +78,19 @@ int pad_read(void)
COMREG = 0x10;
pad_state = 1;
return -1;
}else{
}else if(pad_state==1){
if(SF&1){
return -1;
}
bits = (OREG2<<8) | (OREG3);
IREG0 = 0x40;
bits ^= 0xFFFF;
pad_state = 0;
pad_state = 2;
}else if(pad_state==2){
if((TVSTAT&0x0008)==0){
pad_state = 0;
}
return -1;
}
#endif
@ -271,6 +280,64 @@ int sci_getc(int timeout)
}
/**********************************************************/
void cpu_dmemcpy(void *dst, void *src, int size, int ch)
{
int chcr = 0x5a11;
if(((u32)src&0xfff8703f)==0x25800000){
// CDBLOCK的DATA_PORT
chcr &= 0xcfff;
}
while((CHCR0&0x03)==0x01);
CHCR0 = 0;
DMAOR = 1;
SAR0 = (u32)src;
DAR0 = (u32)dst;
TCR0 = (size+3)>>2;
CHCR0 = chcr;
}
#if 1
void scu_dmemcpy(void *dst, void *src, int size, int ch)
{
volatile SCUDMA_REG *sdma = (SCUDMA_REG *)(SCU_DMA_BASE+ch*0x20);
int mask = 0x0030;
int maskh = 0x0001;
if(ch>0){ mask <<= 4; maskh <<= 1; }
if(ch>1){ mask <<= 4; maskh = 0; }
mask |= maskh<<16;
while(SDSTAT&mask); // 等待传输结束
sdma->src = (u32)src;
sdma->dst = (u32)dst;
sdma->count = size;
sdma->addv = (((u32)dst&0x00f00000)==0) ? 0x102 : 0x101;
sdma->mode = 0x07;
sdma->enable = 0x101;
}
#else
void scu_dmemcpy(void *dst, void *src, int size, int ch)
{
while(SDSTAT&0x10030); // 等待传输结束
SD0R = (u32)src;
SD0W = (u32)dst;
SD0C = size;
SD0AD = (((u32)dst&0x00f00000)==0) ? 0x102 : 0x101;
SD0MD = 0x07;
SD0EN = 0x101;
}
#endif
/**********************************************************/
int read_file (char *name, int offset, int size, void *buf)
@ -297,10 +364,11 @@ int read_file (char *name, int offset, int size, void *buf)
if(retv<0)
return retv;
size = LE32((void*)(TMPBUFF_ADDR+0x04));
if(bus_addr<0x02000000 || bus_addr>=0x03000000){
memcpy(buf, (void*)(TMPBUFF_ADDR+0x0100), size);
}
size = LE32((void*)(TMPBUFF_ADDR+0x04));
return size;
}
@ -402,30 +470,86 @@ int mem_test(int size)
/**********************************************************/
static int last_w, last_h, last_f;
static int cover_top = 1;
void gif_timer(void)
{
if((TVSTAT&0x0008)==0)
return;
int gif_flag = *(u8*)0x22400000;
if(gif_flag){
u8 *dst = (u8*)(VDP2_VRAM+0x20000);
u8 *src = (u8*)(0x22401000);
int w = LE16((u8*)0x22400004);
int h = LE16((u8*)0x22400006);
int x = (fbw-w)/2;
int y = (fbh-h)/2;
if(x<0){
src -= x;
}else{
dst += x;
int src_llen = (gif_flag>=3)? 128 : 512;
int img_w = LE16((u8*)0x22400004);
int img_h = LE16((u8*)0x22400006);
int img_x = (short)LE16((u8*)0x22400008);
int img_y = (short)LE16((u8*)0x2240000a);
int adj_x = (short)LE16((u8*)0x2240000c);
int adj_y = (short)LE16((u8*)0x2240000e);
//printk("img: (%d,%d) %dx%d\n", img_x, img_y, img_w, img_h);
//if( (last_f!=gif_flag) ){
// printk("gflag: %d\n", gif_flag);
//}
if( (last_f!=gif_flag) || (gif_flag>=3 && (last_w>img_w || last_h>img_h)) ){
memset(dst, 0, 240*512);
}
if(y<0){
src -= y*512;
h = fbh;
}else{
dst += y*512;
last_f = gif_flag;
last_w = img_w;
last_h = img_h;
src += img_y*src_llen+img_x;
img_x += adj_x;
if(img_x<0){
src -= img_x;
img_w += img_x;
img_x = 0;
}
if(img_x+img_w>fbw){
img_w = fbw-img_x;
}
memcpy(dst, src, 512*h);
img_y += adj_y;
if(img_y<0){
src -= img_y*512;
img_h += img_y;
img_y = 0;
}
if(img_y+img_h>fbh){
img_h = fbh-img_y;
}
#if 1
if(cover_top){
if(gif_flag==3){
PRINA = 0x0706;
CCCTL = 0x0000;
BGON = 0x0203;
vdp2_win0(1, 1, img_x, img_y, img_x+img_w-1, img_y+img_h-1);
}else{
vdp2_win0(-1, 0, 0, 0, 0, 0);
PRINA = 0x0707;
CCCTL = 0x0002;
BGON = 0x0003;
}
}
#endif
dst += img_y*512+img_x;
//int start = get_timer();
for(int y=0; y<img_h; y++){
scu_dmemcpy(dst, src, img_w, 2);
dst += 512;
src += src_llen;
}
//int end = get_timer();
//printk("gt: %d ms\n", TICK2MS(end-start));
*(u8*)0x22400000 = 0;
}
@ -442,6 +566,23 @@ void gif_timer(void)
}
static void change_cover_layer(void)
{
if(cover_top==0){
vdp2_win0(-1, 0, 0, 0, 0, 0);
PRINA = 0x0707;
CCCTL = 0x0002;
BGON = 0x0003;
}else if(last_f==3){
PRINA = 0x0706;
CCCTL = 0x0000;
BGON = 0x0203;
int x = 176;
int y = (last_h>128)? 24 : 88;
vdp2_win0(1, 1, x, y, x+last_w-1, y+last_h-1);
}
}
/**********************************************************/
static int total_disc, total_page, page;
@ -486,6 +627,15 @@ static void fill_selmenu(void)
}
static void select_notify(int index)
{
if(sel_mode==0){
SS_ARG = page*MENU_ITEMS + index;
SS_CMD = SSCMD_SELECT;
}
}
static void page_update(int up)
{
MENU_DESC *menu = &sel_menu;
@ -494,6 +644,7 @@ static void page_update(int up)
fill_selmenu();
menu->current = (up)? menu->num-1: 0;
select_notify(menu->current);
draw_menu_frame(menu);
}
@ -541,28 +692,28 @@ static int sel_handle(int ctrl)
if(BUTTON_DOWN(ctrl, PAD_UP)){
if(menu->current>0){
menu->current -= 1;
menu_update(menu);
select_notify(menu->current-1);
menu_update(menu, menu->current-1);
}else if(page>0){
page -= 1;
page_update(1);
}else if(total_page>0){
}else if(total_page>1){
page = total_page-1;
page_update(1);
}
}else if(BUTTON_DOWN(ctrl, PAD_DOWN)){
if(menu->current<(menu->num-1)){
menu->current += 1;
menu_update(menu);
select_notify(menu->current+1);
menu_update(menu, menu->current+1);
}else if((page+1)<total_page){
page += 1;
page_update(0);
}else{
}else if(total_page>1){
page = 0;
page_update(0);
}
}else if(BUTTON_DOWN(ctrl, PAD_LT)){
if(total_page>0){
if(total_page>1){
page -= 1;
if(page<0){
page = total_page-1;
@ -570,7 +721,7 @@ static int sel_handle(int ctrl)
page_update(0);
}
}else if(BUTTON_DOWN(ctrl, PAD_RT)){
if(total_page>0){
if(total_page>1){
page += 1;
if(page>=total_page){
page = 0;
@ -588,7 +739,10 @@ static int sel_handle(int ctrl)
SS_CMD = SSCMD_LOADDISC;
while(SS_CMD);
retv = bios_cd_cmd(0);
retv = SS_ARG;
if(retv==0){
retv = bios_cd_cmd(0);
}
if(retv){
char buf[40];
sprintf(buf, TT("游戏启动失败! %d"), retv);
@ -603,14 +757,32 @@ static int sel_handle(int ctrl)
menu_status(menu, buf);
}
}
}else if(BUTTON_DOWN(ctrl, PAD_Z) && (sel_mode==0)){
}else if(BUTTON_DOWN(ctrl, PAD_Z)){
int index = page*MENU_ITEMS + menu->current;
int retv;
SS_ARG = index;
SS_CMD = SSCMD_LOADDISC;
while(SS_CMD);
if(sel_mode==0){
int index = page*MENU_ITEMS + menu->current;
my_cdplayer();
SS_ARG = index;
SS_CMD = SSCMD_LOADDISC;
while(SS_CMD);
use_sys_load = 0;
my_cdplayer();
}else{
menu_status(menu, TT("加载文件中......"));
cdblock_on(0);
retv = run_binary(index, 1);
if(retv){
char buf[40];
sprintf(buf, TT("文件加载失败! %d"), retv);
menu_status(menu, buf);
}
}
}else if(BUTTON_DOWN(ctrl, PAD_LEFT)){
cover_top ^= 1;
change_cover_layer();
}else if(BUTTON_DOWN(ctrl, PAD_C)){
return MENU_EXIT;
}
@ -629,8 +801,11 @@ void select_game(void)
sel_menu.handle = sel_handle;
fill_selmenu();
select_notify(sel_menu.current | SELECT_ENTER);
menu_run(&sel_menu);
select_notify(SELECT_EXIT);
}
@ -730,7 +905,9 @@ int main_handle(int ctrl)
return MENU_EXIT;
}
if(!BUTTON_DOWN(ctrl, PAD_A))
if(!BUTTON_DOWN(ctrl, PAD_A) && !BUTTON_DOWN(ctrl, PAD_C))
return 0;
if(BUTTON_DOWN(ctrl, PAD_C) && index!=2)
return 0;
if(index==0){
@ -738,31 +915,62 @@ int main_handle(int ctrl)
select_category();
return MENU_RESTART;
}else if(index==1){
write_file("/SAROO/SS_BUP.BIN", 0, 0x10000, (void*)0x20180000);
cdblock_on(0);
bios_run_cd_player();
use_sys_bup = 1;
use_sys_load = 1;
my_cdplayer();
return MENU_RESTART;
}else if(index==2){
int type = 4;
menu_status(&main_menu, TT("检查光盘中......"));
cdblock_on(1);
int retv = cdblock_check();
//int retv = cdblock_check();
int retv = jhl_auth_hack(100000);
if(retv<0){
menu_status(&main_menu, TT("未发现光盘!"));
cdblock_off();
return 0;
}else if(retv==1){
// 是Audio CD
use_sys_bup = 1;
use_sys_load = 1;
my_cdplayer();
}else if(retv==2){
type = 2;
}else if(retv==3){
// 是刻录游戏CD
retv = jhl_auth_hack(100000);
if(retv!=2){
char buf[64];
sprintf(buf, "%s%d", TT("不是游戏光盘!"), retv);
menu_status(&main_menu, buf);
cdblock_off();
return 0;
}
type = 2;
}else if(retv!=4){
menu_status(&main_menu, TT("不是游戏光盘!"));
// 是数据CD
char buf[64];
sprintf(buf, "%s%d", TT("不是游戏光盘!"), retv);
menu_status(&main_menu, buf);
cdblock_off();
return 0;
}
// 停止正在播放的背景音乐。
SS_ARG = 0xffff;
SS_CMD = SSCMD_LOADDISC;
menu_status(&main_menu, TT("游戏启动中......"));
retv = bios_cd_cmd(4);
if(BUTTON_DOWN(ctrl, PAD_C)){
type |= 0x80;
}
retv = bios_cd_cmd(type);
if(retv){
char buf[40];
sprintf(buf, TT("游戏启动失败! %d"), retv);
menu_status(&main_menu, buf);
// CDBlock Off, SAROOO On
smpc_cmd(CDOFF);
SS_CTRL = SAROO_EN | CS0_RAM4M;
cdblock_off();
}
return 0;
}else if(index==3){
@ -832,6 +1040,56 @@ void menu_init(void)
}
/**********************************************************/
// Sega Saturn 1.00J : BTR_1.00D1940921 0
// Victor Saturn 1.00: BTR_1.00DJ941018 1
//
// Sega Saturn 1.00a : BTR_1.000U941115 2 40417:f4
// Sega Saturn 1.01a : BTR_1.000U941115 3 40417:54
// Samsung Saturn : BTR_1.000U941115 4 40417:84
//
// Sega Saturn 1.01J : BTR_1.0191941228 5
// V-Saturn 1.01J : BTR_1.019J950703 6
// HI-Saturn 1.01J : BTR_1.019H950130 7
// HI-Saturn 1.02J : BTR_1.020H950519 8
// HI-Saturn 1.03 : BTRF1.030H950720 9
//
// Sega Saturn 1.003 : BTRD1.0032941012 10
//
static char *bvstr[12] = {"0D1","0DJ","00U","00U","00U","191","19J","19H","20H","30H","032",};
void detect_bios_type(void)
{
int i;
char *bv = (char*)0x0807;
for(i=0; i<11; i++){
if(strncmp(bv, bvstr[i], 3)==0){
bios_type = i;
break;
}
}
if(i==11){
bios_type = BIOS_UNKNOW;
return;
}
if(bios_type==BIOS_100A){
if(*(u8*)(0x40417)==0x54){
bios_type = BIOS_101A;
}else if(*(u8*)(0x40417)==0x84){
bios_type = BIOS_SAMS;
}
}
}
/**********************************************************/
int _main(void)
{
// EFSDL/EFPAN for CDDA
@ -840,6 +1098,8 @@ int _main(void)
// Master Volume
*(u16*)(0x25b00400) = 0x020f;
detect_bios_type();
SS_ARG = 0;
SS_CMD = SSCMD_STARTUP;
@ -853,17 +1113,22 @@ int _main(void)
lang_id = LE32((void*)(SYSINFO_ADDR+0x04));
debug_flag = LE32((void*)(SYSINFO_ADDR+0x08));
// restore bios_loadcd_init1
// restore bios function
*(u32*)(0x06000288) = 0x000018a8; // bios_loadcd_boot
*(u32*)(0x0600028c) = 0x00001874; // bios_loadcd_readip
*(u32*)(0x0600029c) = 0x00001904; // bios_loadcd_init
*(u32*)(0x060002dc) = *(u32*)(0x2000111c);
*(u32*)(0x02000f04) = (u32)cdc_read_sector;
*(u32*)(0x02000f08) = (u32)read_file;
*(u32*)(0x02000f0c) = (u32)write_file;
*(u32*)(0x02000f24) = (u32)conio_getc;
*(u32*)(0x02000f30) = (u32)bios_cd_cmd;
*(u32*)(0x02000f34) = (u32)page_update;
*(u32*)(0x02000f38) = (u32)sci_init;
*(u32*)(0x02000f3c) = (u32)printk;
sys_bup_init = (void*)*(u32*)(0x20000958);
if(debug_flag&0x0001){
// sci_putc
@ -873,6 +1138,7 @@ int _main(void)
printk(" SS ver: %08x\n", get_build_date());
printk(" FPGA ver: %08x\n", SS_VER);
printk(" lang_id: %d\n", lang_id);
printk(" bios_type: %d\n", bios_type);
}else if(debug_flag&0x0004){
// conio_putc
}else if(debug_flag&0x0008){

View file

@ -48,6 +48,10 @@ typedef unsigned long long u64;
#define SSCMD_LMEMS 0x000b
#define SSCMD_SMEMS 0x000c
#define SSCMD_STARTUP 0x000d
#define SSCMD_SELECT 0x000e
#define SELECT_ENTER 0x8000
#define SELECT_EXIT 0x4000
#define IMGINFO_ADDR 0x22080000
@ -117,9 +121,9 @@ typedef struct {
#define bios_run_cd_player INDIRECT_CALL(0x0600026C, void, void)
#define bios_loadcd_init1 INDIRECT_CALL(0x060002dc, int, int) // 00002650
#define bios_loadcd_init INDIRECT_CALL(0x0600029c, int, int) // 00001904
#define bios_loadcd_init INDIRECT_CALL(0x0600029c, int, void) // 00001904
#define bios_loadcd_read INDIRECT_CALL(0x060002cc, int, void) // 00001912
#define bios_loadcd_boot INDIRECT_CALL(0x06000288, int, void) // 000018A8
#define bios_loadcd_boot INDIRECT_CALL(0x06000288, int, void) // 000018A8
//!< mode 0 -> check, 1 -> do auth
#define bios_check_cd_auth INDIRECT_CALL(0x06000270, int, int mode)
@ -162,6 +166,7 @@ void cdc_trans_data(u8 *buf, int length);
int cdc_auth_status(int *status);
int cdc_auth_device(void);
int jhl_auth_hack(int delay);
int cdc_change_dir(int selnum, int fid);
int cdc_read_dir(int selnum, int fid);
@ -188,8 +193,26 @@ int cdc_read_sector(int fad, int size, u8 *buf);
void my_cdplayer(void);
void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg);
extern void (*sys_bup_init)(u8*, u8*, void*);
extern int use_sys_bup;
extern int use_sys_load;
enum{
BIOS_100J,
BIOS_100V,
BIOS_100A,
BIOS_101A,
BIOS_SAMS,
BIOS_101J,
BIOS_101V,
BIOS_101H,
BIOS_102H,
BIOS_103H,
BIOS_1003,
BIOS_UNKNOW,
};
extern int bios_type;
/*****************************************************************************/
@ -197,6 +220,7 @@ extern const int HZ;
#define MS2TICK(ms) ( (ms) * HZ / 1000)
#define TICK2MS(tk) ( (tk) * 1000 / HZ)
#define TICK2US(tk) ( (tk) * 1000*1000 / HZ)
void reset_timer(void);
u32 get_timer(void);
@ -204,6 +228,8 @@ void usleep(u32 us);
void msleep(u32 ms);
void cpu_dmemcpy(void *to, void *from, int size, int ch);
void scu_dmemcpy(void *dst, void *src, int size, int ch);
/*****************************************************************************/
@ -251,6 +277,7 @@ void nbg1_on(void);
void nbg1_set_cram(int index, int r, int g, int b);
void nbg1_put_pixel(int x, int y, int color);
void vdp2_win0(int scr, int outside, int sx, int sy, int ex, int ey);
/*****************************************************************************/
@ -386,7 +413,7 @@ int menu_run(MENU_DESC *menu);
void menu_status(MENU_DESC *menu, char *string);
void draw_menu_frame(MENU_DESC *menu);
void menu_update(MENU_DESC *menu);
void menu_update(MENU_DESC *menu, int new);
int menu_default(MENU_DESC *menu, int ctrl);

View file

@ -360,9 +360,14 @@ void sci_shell(void)
CMD(c) {
/* 打开系统光驱 */
cdblock_on(1);
}
CMD(auth){
int retv = cdblock_check();
printk("cdblock_check: %d\n", retv);
}
CMD(jhl){
jhl_auth_hack(arg[0]);
}
CMD(s) {
/* 关闭系统光驱, 打开sarooo */
cdblock_off();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

250
Firm_Saturn/slogo.h Normal file
View file

@ -0,0 +1,250 @@
#ifndef __logo_dat__
#define __logo_dat__
static unsigned int size_logo_dat = 3872;
static unsigned char logo_dat[] __attribute__((aligned(16))) = {
0x80, 0x00, 0xc0, 0x20, 0xbc, 0xa0, 0xd0, 0xe0, 0xdd, 0x60, 0xe1, 0xc0, 0xea, 0x00, 0xd9, 0xc8,
0xf2, 0x40, 0xf6, 0xa0, 0xfe, 0xe0, 0xf2, 0xca, 0xf7, 0x32, 0xf7, 0x7a, 0xff, 0xdd, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x28, 0xdf, 0x00, 0x00, 0x8e, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x22, 0x02, 0x46, 0xbc, 0xcc,
0x5b, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x73, 0x33, 0xfb, 0x34, 0x44, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0xcc, 0xcc, 0xcc, 0xcc,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x55, 0x55, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x30, 0xcc, 0xcc, 0xcc, 0x50,
0xff, 0xff, 0xff, 0x50, 0xff, 0xff, 0xff, 0x60, 0x33, 0x3c, 0xff, 0x60, 0x55, 0x4c, 0xff, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x06, 0xcf, 0x00, 0x00, 0x5c, 0xff, 0x00, 0x02, 0xbf, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x10, 0x58, 0xbc, 0xcc, 0xb5,
0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x43, 0x33, 0x7e, 0x44, 0x45, 0x54, 0x43,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0xc6, 0x20, 0x00, 0x00, 0xff, 0x83, 0x00, 0x00, 0xff, 0xf8, 0x20, 0x00, 0xcf, 0xfe, 0x60, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x22, 0x22, 0x22, 0x18, 0xcc, 0xcc, 0xcc,
0x1b, 0xff, 0xff, 0xff, 0x2b, 0xff, 0xff, 0xff, 0x2b, 0xff, 0x73, 0x33, 0x2b, 0xff, 0x75, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0xcc, 0xcc, 0xcc, 0xcc,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x55, 0x55, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x21, 0x00, 0xcc, 0xcc, 0xbb, 0x54,
0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x47, 0xcf, 0x55, 0x55, 0x44, 0x43,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0xb5, 0x20, 0x00, 0x00, 0xff, 0xb5, 0x00, 0x00, 0xff, 0xfc, 0x60, 0x00, 0xbf, 0xff, 0xd8, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0x59,
0x00, 0x25, 0xbe, 0xff, 0x04, 0x8f, 0xff, 0xff, 0x4b, 0xff, 0xff, 0xc7, 0x9f, 0xff, 0xc3, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0xbc, 0xcc, 0xcc, 0xcc,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x43, 0x33, 0x33, 0x33, 0x45, 0x55, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x21, 0x00, 0x00, 0xcc, 0xbb, 0x54, 0x20,
0xff, 0xff, 0xfe, 0xb5, 0xff, 0xff, 0xff, 0xff, 0x33, 0x47, 0xcf, 0xff, 0x55, 0x44, 0x43, 0xbf,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x20, 0x00, 0x02, 0x5b, 0x94, 0x00, 0x49, 0xff, 0xfb, 0x44, 0xbf, 0xff, 0xff, 0x99, 0xff, 0xfb,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x22, 0x22, 0x45, 0xbb, 0xcc, 0xcc,
0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x74, 0x33, 0x33, 0x34, 0x44, 0x55, 0x55,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x10, 0xcc, 0xcc, 0xcb, 0x95,
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x34, 0x7c, 0x55, 0x55, 0x54, 0x44,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0xeb, 0x52, 0x00, 0x00, 0xff, 0xf8, 0x40, 0x00, 0xff, 0xff, 0xb4, 0x00, 0x3c, 0xff, 0xf9, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0xdf, 0xfe, 0x00, 0x6c, 0xff, 0xe4, 0x02, 0xaf, 0xff, 0x58, 0x08, 0xdf, 0xf9, 0x89,
0x0a, 0xff, 0xd6, 0xaa, 0x4c, 0xff, 0xba, 0xaa, 0x8d, 0xff, 0x8a, 0xaa, 0xaf, 0xfd, 0x9a, 0xaa,
0x44, 0x56, 0x66, 0x86, 0x58, 0x88, 0x88, 0x88, 0x98, 0x98, 0x88, 0x89, 0x99, 0x99, 0xdf, 0xff,
0xa9, 0xbf, 0xec, 0xb9, 0xaa, 0xfc, 0x66, 0x88, 0xaf, 0xd6, 0x9a, 0xaa, 0xaf, 0x89, 0xaa, 0xaa,
0x86, 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff,
0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0x86, 0x6c, 0xff, 0x80, 0x88, 0x6c, 0xff, 0x90, 0x99, 0x8c, 0xff, 0xa0, 0xff, 0xff, 0xff, 0xa0,
0x99, 0x9d, 0xff, 0xa0, 0x88, 0x8c, 0xff, 0xa0, 0xaa, 0xac, 0xff, 0xa0, 0xaa, 0xac, 0xff, 0xa0,
0x00, 0x08, 0xef, 0xf4, 0x00, 0x2a, 0xff, 0xc5, 0x00, 0x5c, 0xff, 0x68, 0x00, 0xaf, 0xfe, 0x69,
0x02, 0xbf, 0xfc, 0x9a, 0x08, 0xdf, 0xf8, 0xaa, 0x0a, 0xff, 0xd9, 0xaa, 0x3b, 0xff, 0xba, 0xaa,
0x56, 0x68, 0x68, 0x66, 0x88, 0x88, 0x88, 0x88, 0x89, 0x88, 0x88, 0x89, 0x99, 0xaf, 0xfd, 0x99,
0xa9, 0xdd, 0x9f, 0xa9, 0xaa, 0xf8, 0x6c, 0xda, 0xac, 0xe9, 0xa9, 0xfa, 0xae, 0xca, 0xa8, 0xfb,
0x4d, 0xff, 0xb2, 0x00, 0x65, 0xff, 0xd6, 0x00, 0x86, 0xdf, 0xfa, 0x00, 0x99, 0xbf, 0xfc, 0x40,
0xa9, 0x8f, 0xfe, 0x90, 0xaa, 0x9c, 0xff, 0xa0, 0xaa, 0xab, 0xff, 0xc4, 0xaa, 0xa8, 0xff, 0xe9,
0x2b, 0xff, 0x96, 0x68, 0x2b, 0xff, 0x98, 0x88, 0x2b, 0xff, 0x98, 0x88, 0x2b, 0xff, 0xff, 0xff,
0x2b, 0xff, 0xbb, 0xbb, 0x2b, 0xff, 0x98, 0x88, 0x2b, 0xff, 0xba, 0xaa, 0x2b, 0xff, 0xba, 0xaa,
0x68, 0x68, 0x68, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xbb, 0xbb, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0x68, 0x68, 0x68, 0x65, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0xff, 0xfc, 0x99,
0xbb, 0xbb, 0xcf, 0xfa, 0x88, 0x88, 0x66, 0xdf, 0xaa, 0xaa, 0xa9, 0x6d, 0xaa, 0xaa, 0xaa, 0x99,
0x44, 0xff, 0xfd, 0x68, 0x85, 0x4e, 0xff, 0xbb, 0x98, 0x65, 0xff, 0xfd, 0x99, 0x98, 0xbf, 0xff,
0x9a, 0xa9, 0x6d, 0xff, 0xaa, 0xaa, 0xab, 0xff, 0xea, 0xaa, 0xa8, 0xff, 0xfa, 0xaa, 0xa9, 0xdf,
0xef, 0xfb, 0x45, 0x66, 0xff, 0xc4, 0x88, 0x88, 0xff, 0x58, 0x89, 0x88, 0xfc, 0x89, 0x99, 0x9b,
0xfb, 0x9a, 0xa9, 0xbf, 0xf9, 0xaa, 0xaa, 0xfe, 0xf9, 0xaa, 0xab, 0xf9, 0xf9, 0xaa, 0xac, 0xf8,
0x68, 0x68, 0x68, 0x68, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0xef, 0xff, 0xff, 0xff,
0xfb, 0x99, 0x99, 0x99, 0x66, 0x88, 0x88, 0x88, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0x68, 0x68, 0x65, 0x47, 0x88, 0x88, 0x88, 0x85, 0x98, 0x88, 0x88, 0x98, 0xff, 0xeb, 0x99, 0x99,
0x9b, 0xef, 0xc9, 0xaa, 0x86, 0x5d, 0xfa, 0xaa, 0xaa, 0x98, 0xfb, 0xaa, 0xaa, 0xa8, 0xfc, 0xaa,
0xff, 0xee, 0xff, 0x74, 0xbf, 0xff, 0xfb, 0x48, 0x5f, 0xff, 0xf5, 0x88, 0x8c, 0xff, 0xc8, 0x99,
0xab, 0xff, 0x99, 0xaa, 0xa9, 0xff, 0x9a, 0xaa, 0xa9, 0xff, 0x9a, 0xaa, 0xa9, 0xfe, 0x9a, 0xaa,
0x56, 0x68, 0x68, 0x68, 0x88, 0x88, 0x88, 0x88, 0x98, 0x88, 0x89, 0x99, 0x99, 0xbf, 0xff, 0xff,
0x9c, 0xfe, 0xb9, 0x99, 0xaf, 0xd5, 0x68, 0x88, 0xcf, 0x89, 0xaa, 0xaa, 0xcf, 0x8a, 0xaa, 0xaa,
0x68, 0x68, 0x68, 0x66, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x88, 0x89, 0xff, 0xff, 0xfe, 0xb9,
0x99, 0x99, 0xbf, 0xfb, 0x88, 0x88, 0x66, 0xef, 0xaa, 0xaa, 0xa9, 0x9f, 0xaa, 0xaa, 0xaa, 0x8f,
0x54, 0x7f, 0xfe, 0x80, 0x88, 0x4c, 0xff, 0xb3, 0x89, 0x85, 0xff, 0xe9, 0x99, 0x98, 0xcf, 0xfa,
0x9a, 0xa9, 0xbf, 0xfb, 0xaa, 0xaa, 0x9f, 0xfc, 0xba, 0xaa, 0x9f, 0xfc, 0xca, 0xaa, 0x9f, 0xfd,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaf, 0xfc, 0xaa, 0xaa, 0xaf, 0xfc, 0xaa, 0xaa, 0xaf, 0xfc, 0xaa, 0xaa, 0xaf, 0xfc, 0xaa, 0xaa,
0xaf, 0xfd, 0x99, 0xaa, 0x6d, 0xff, 0x99, 0x99, 0x3c, 0xff, 0xb9, 0x99, 0x0a, 0xff, 0xd8, 0x89,
0xcf, 0x8a, 0xaa, 0xaa, 0xce, 0x9a, 0xaa, 0xaf, 0xce, 0x9a, 0xaa, 0xac, 0xbf, 0xaa, 0xaa, 0x96,
0x8f, 0xc9, 0x9a, 0x9a, 0x8c, 0xfa, 0x99, 0x99, 0x95, 0xdf, 0xc9, 0x99, 0x88, 0x5c, 0xff, 0xdb,
0xaa, 0xaa, 0xaa, 0xaa, 0xee, 0xee, 0xfe, 0xef, 0xef, 0xff, 0xff, 0xff, 0x66, 0x9c, 0xef, 0xff,
0x98, 0x86, 0x5b, 0xff, 0x99, 0x99, 0x86, 0x5d, 0x98, 0x99, 0x99, 0x85, 0x98, 0x89, 0x89, 0x98,
0xaa, 0x9c, 0xff, 0xa0, 0xff, 0xef, 0xff, 0xa0, 0xff, 0xff, 0xff, 0xa3, 0xfd, 0xdd, 0xdd, 0xa9,
0xfe, 0x98, 0x66, 0x8a, 0xff, 0xe9, 0x00, 0x3c, 0xdf, 0xfc, 0x60, 0x9e, 0x5f, 0xff, 0xa3, 0xaf,
0x9d, 0xff, 0x8a, 0xaa, 0xaf, 0xfd, 0x9a, 0xaa, 0xcf, 0xfb, 0xaa, 0xaa, 0xef, 0xf8, 0xaa, 0xaa,
0xff, 0xc9, 0xaa, 0xac, 0xff, 0xb9, 0x99, 0x9f, 0xff, 0x69, 0x99, 0xaf, 0xfc, 0x89, 0x88, 0xcd,
0xaf, 0x8a, 0xa9, 0xcd, 0xcd, 0x9a, 0xaa, 0x9f, 0xfb, 0xaa, 0xaa, 0x8e, 0xf8, 0xaa, 0xaa, 0xac,
0xd9, 0xaa, 0xaa, 0xa8, 0xb9, 0x99, 0x99, 0xa8, 0x69, 0x99, 0x99, 0x99, 0x89, 0x98, 0xc8, 0x89,
0xaa, 0xa9, 0xcf, 0xfa, 0xaa, 0xaa, 0x9f, 0xfc, 0xca, 0xaa, 0x8e, 0xff, 0xea, 0xaa, 0x9c, 0xff,
0xfa, 0xaa, 0xa8, 0xff, 0xec, 0x99, 0xa8, 0xef, 0xbf, 0x89, 0x99, 0xbf, 0x6f, 0x98, 0x89, 0x6f,
0x4b, 0xff, 0xba, 0xaa, 0x9b, 0xff, 0xba, 0xaa, 0xab, 0xff, 0xba, 0xaa, 0xab, 0xff, 0xba, 0xaa,
0xcb, 0xff, 0xba, 0xaa, 0xfa, 0xff, 0xb9, 0x99, 0xfc, 0xff, 0xb9, 0x99, 0xfe, 0xff, 0xb8, 0x89,
0xaa, 0xaa, 0xaa, 0xaa, 0xad, 0xee, 0xee, 0xee, 0xae, 0xed, 0xdd, 0xdd, 0xae, 0xc6, 0x66, 0x66,
0x9e, 0xc9, 0x9a, 0x99, 0x9e, 0xc9, 0x99, 0x99, 0x8e, 0xc9, 0x99, 0x99, 0x8e, 0xc8, 0x89, 0x89,
0xaa, 0xaa, 0xaa, 0xa8, 0xee, 0xea, 0xaa, 0xa9, 0xdd, 0xda, 0xaa, 0xa9, 0x66, 0x69, 0xaa, 0xaa,
0xa9, 0xa9, 0xa9, 0xab, 0x99, 0x99, 0x99, 0x9f, 0x99, 0x99, 0x99, 0xef, 0x89, 0xbb, 0xcf, 0xf6,
0xfc, 0xaa, 0xaa, 0xcf, 0xfc, 0xaa, 0xaa, 0xcf, 0xfc, 0xaa, 0xaa, 0xcf, 0xfb, 0xaa, 0xaa, 0xcf,
0xf9, 0xaa, 0x99, 0xdf, 0xd8, 0xa9, 0x99, 0xff, 0x69, 0x99, 0x9a, 0xff, 0x89, 0x89, 0x8d, 0xff,
0xf9, 0xaa, 0xac, 0xf9, 0xf9, 0xaa, 0xac, 0xf9, 0xf9, 0xaa, 0xac, 0xf9, 0xf9, 0xaa, 0xac, 0xf9,
0xf9, 0xaa, 0xac, 0xf9, 0xf9, 0x99, 0x9c, 0xf9, 0xf8, 0x99, 0x9c, 0xf8, 0xf8, 0x98, 0x8c, 0xf8,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xff, 0xfb, 0xaa, 0xac, 0xff, 0xfc, 0xaa, 0xab, 0xff, 0xfc,
0xaa, 0xab, 0xff, 0xfc, 0x99, 0x9b, 0xff, 0xfc, 0x99, 0x9b, 0xff, 0xfb, 0x98, 0x8b, 0xff, 0xfb,
0xaa, 0xa9, 0xec, 0xaa, 0xaa, 0xa9, 0xec, 0xaa, 0xaa, 0xa9, 0xec, 0xaa, 0xaa, 0xaa, 0xec, 0xaa,
0xaa, 0xa9, 0xec, 0x99, 0x99, 0x99, 0xec, 0x99, 0x99, 0x98, 0xec, 0x99, 0x88, 0x88, 0xec, 0x88,
0xa9, 0xee, 0x9a, 0xaa, 0xa9, 0xee, 0xaa, 0xaa, 0xa9, 0xee, 0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa,
0xa9, 0xee, 0x9a, 0x99, 0x99, 0xee, 0x99, 0x99, 0x98, 0xee, 0x89, 0x99, 0x88, 0xee, 0x88, 0x88,
0xce, 0x9a, 0xaa, 0xaa, 0xce, 0xaa, 0xaa, 0xbf, 0xce, 0xaa, 0xaa, 0xcf, 0xce, 0xaa, 0xaa, 0xcf,
0xce, 0x9a, 0xaa, 0xcf, 0xce, 0x99, 0x99, 0xcf, 0xce, 0x89, 0x99, 0xcf, 0xce, 0x88, 0x88, 0xcf,
0xaa, 0xaa, 0xaa, 0x9f, 0xff, 0xaa, 0xaa, 0x9f, 0xff, 0xba, 0xaa, 0x9f, 0xff, 0xba, 0xaa, 0x9f,
0xff, 0xba, 0xaa, 0x9f, 0xff, 0xb9, 0x99, 0x9f, 0xff, 0xb9, 0x99, 0x8f, 0xff, 0xb8, 0x89, 0x8f,
0xca, 0xaa, 0x9f, 0xfd, 0xca, 0xaa, 0x9f, 0xfd, 0xca, 0xaa, 0x9f, 0xfd, 0xca, 0xaa, 0x9f, 0xfd,
0xca, 0xaa, 0x9f, 0xfd, 0xc9, 0x99, 0x9f, 0xfd, 0xc9, 0x99, 0x8f, 0xfd, 0xc8, 0x89, 0x8f, 0xfd,
0x60, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
0x06, 0xdf, 0xfb, 0x88, 0x01, 0x9f, 0xff, 0x88, 0x00, 0x4b, 0xff, 0xf6, 0x33, 0x36, 0xcf, 0xff,
0xbc, 0xcc, 0xbf, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xcf, 0xf3, 0x33, 0x33,
0x88, 0x85, 0x5b, 0xdf, 0x86, 0x88, 0x65, 0x44, 0x68, 0x66, 0x66, 0x66, 0xb5, 0x66, 0x66, 0x66,
0xfd, 0xb6, 0x55, 0x56, 0xff, 0xff, 0xec, 0xb6, 0xff, 0xff, 0xff, 0xfd, 0x33, 0x33, 0x43, 0x44,
0xff, 0xc8, 0x88, 0x88, 0x6b, 0xff, 0xb6, 0x88, 0x54, 0x4c, 0xfb, 0x66, 0x65, 0x54, 0xdf, 0x66,
0x66, 0x65, 0x4f, 0xb6, 0x55, 0x55, 0x4f, 0xc5, 0x55, 0x55, 0x4e, 0xc5, 0x55, 0x54, 0x4f, 0xb5,
0x67, 0xff, 0xc8, 0xcf, 0x85, 0xdf, 0xf6, 0xff, 0x66, 0xbf, 0xfb, 0xff, 0x66, 0x5f, 0xff, 0xff,
0x66, 0x4f, 0xff, 0xfe, 0x55, 0x5e, 0xff, 0xfb, 0x55, 0x4e, 0xff, 0xf4, 0x55, 0x4e, 0xff, 0xd4,
0xf8, 0x88, 0x88, 0xfb, 0xe5, 0x88, 0x8b, 0xf5, 0xc6, 0x66, 0x6d, 0xc6, 0x56, 0x66, 0x6f, 0x76,
0x46, 0x66, 0xbf, 0x46, 0x55, 0x55, 0xdc, 0x55, 0x55, 0x55, 0xf7, 0x55, 0x55, 0x5b, 0xf3, 0x55,
0x88, 0x8b, 0xf8, 0x88, 0x88, 0x8c, 0xf8, 0x88, 0x86, 0x6f, 0xfb, 0x66, 0x66, 0x9f, 0xfe, 0x56,
0x55, 0xcf, 0xff, 0x66, 0x55, 0xff, 0xff, 0xb5, 0x56, 0xff, 0xff, 0xd4, 0x4c, 0xff, 0xff, 0xf5,
0x6d, 0xc8, 0x88, 0x6d, 0x8b, 0xf6, 0x88, 0x8b, 0x85, 0xfb, 0x66, 0x85, 0x65, 0xcd, 0x66, 0x65,
0x65, 0x7f, 0x56, 0x65, 0x55, 0x4f, 0xb5, 0x55, 0x55, 0x4c, 0xd5, 0x55, 0x55, 0x45, 0xf5, 0x55,
0xff, 0xff, 0xb8, 0x88, 0xff, 0xff, 0xb8, 0x88, 0xff, 0xff, 0x96, 0x68, 0xcf, 0xff, 0x96, 0x66,
0x7f, 0xff, 0x96, 0x65, 0x4f, 0xff, 0x75, 0x55, 0x4c, 0xff, 0x75, 0x55, 0x47, 0xff, 0x75, 0x55,
0x8e, 0xc8, 0x88, 0x88, 0x6e, 0xc8, 0x88, 0x88, 0x6e, 0xc6, 0x66, 0x66, 0x5e, 0xc6, 0x66, 0x66,
0x5e, 0xc5, 0x56, 0x65, 0x5e, 0xc5, 0x55, 0x56, 0x4e, 0xc5, 0x55, 0x5c, 0x4e, 0xc4, 0x54, 0x4c,
0x88, 0xff, 0xfc, 0x56, 0x86, 0xbf, 0x54, 0x68, 0x68, 0x4f, 0xe5, 0x86, 0x66, 0x57, 0xfb, 0x66,
0x66, 0x64, 0xdf, 0x56, 0x55, 0x55, 0x4f, 0xc5, 0x55, 0x55, 0x4c, 0xf5, 0xc4, 0x55, 0x53, 0xfd,
0x88, 0x88, 0x9f, 0xff, 0x86, 0x86, 0xef, 0xff, 0x68, 0x6d, 0xff, 0xff, 0x66, 0xbf, 0xfe, 0xcf,
0x66, 0x5d, 0xff, 0xef, 0x55, 0x55, 0xff, 0xff, 0x55, 0x54, 0xcf, 0xff, 0x45, 0x55, 0x4f, 0xff,
0xf6, 0x88, 0x8c, 0xf8, 0xf6, 0x88, 0x8c, 0xf6, 0xf6, 0x86, 0x6c, 0xf6, 0xe5, 0x66, 0x6b, 0xf5,
0xe5, 0x66, 0x5c, 0xf5, 0xe5, 0x55, 0x5b, 0xf5, 0xe4, 0x55, 0x5c, 0xf4, 0xf4, 0x55, 0x4b, 0xf4,
0x88, 0x8b, 0xff, 0xfb, 0x88, 0x8b, 0xff, 0xfb, 0x86, 0x6b, 0xff, 0xfb, 0x66, 0x6b, 0xff, 0xfb,
0x66, 0x6b, 0xff, 0xfb, 0x55, 0x5b, 0xff, 0xfb, 0x55, 0x57, 0xff, 0xfb, 0x55, 0x54, 0x33, 0x34,
0x88, 0x88, 0xec, 0x88, 0x88, 0x86, 0xec, 0x88, 0x66, 0x86, 0xec, 0x66, 0x66, 0x65, 0xec, 0x66,
0x56, 0x65, 0xec, 0x56, 0x55, 0x55, 0xec, 0x55, 0x55, 0x54, 0xec, 0x55, 0x55, 0x54, 0xec, 0x45,
0x88, 0xee, 0x88, 0x88, 0x86, 0xee, 0x68, 0x88, 0x86, 0xee, 0x68, 0x66, 0x65, 0xee, 0x56, 0x66,
0x65, 0xee, 0x56, 0x55, 0x55, 0xee, 0x55, 0x55, 0x54, 0xee, 0x45, 0x55, 0x54, 0xee, 0x45, 0x54,
0xce, 0x88, 0x88, 0xcf, 0xce, 0x68, 0x88, 0xbf, 0xce, 0x68, 0x66, 0xbf, 0xce, 0x56, 0x66, 0xbf,
0xce, 0x55, 0x65, 0xbf, 0xce, 0x55, 0x55, 0xbf, 0xce, 0x45, 0x55, 0xbf, 0xce, 0x45, 0x55, 0x43,
0xff, 0xb8, 0x88, 0x8f, 0xff, 0xb8, 0x88, 0x6f, 0xff, 0xb6, 0x68, 0x6f, 0xff, 0xb6, 0x66, 0x5f,
0xff, 0xb6, 0x66, 0x5f, 0xff, 0xb5, 0x55, 0x5f, 0xff, 0x75, 0x55, 0x4f, 0x33, 0x45, 0x55, 0x4f,
0xb8, 0x88, 0x8f, 0xfd, 0xb8, 0x88, 0x6f, 0xfd, 0xb6, 0x68, 0x6f, 0xfd, 0xb6, 0x66, 0x5f, 0xfd,
0xb5, 0x66, 0x5f, 0xfd, 0xb5, 0x55, 0x5f, 0xfd, 0xb5, 0x55, 0x4f, 0xfd, 0xb4, 0x55, 0x4f, 0xfd,
0x50, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0xcf, 0xf3, 0x44, 0x44, 0xcf, 0xf4, 0x44, 0x44, 0xcf, 0xf3, 0x44, 0x44, 0xcf, 0xf3, 0x33, 0x33,
0xcf, 0xff, 0xff, 0xff, 0xcf, 0xf7, 0x77, 0x77, 0xcf, 0xf1, 0x22, 0x22, 0xcf, 0xf2, 0x33, 0x33,
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x44, 0x34, 0x44, 0x33, 0x33, 0x33, 0x33,
0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33,
0x44, 0x44, 0x5f, 0x74, 0x44, 0x43, 0xdf, 0x34, 0x44, 0x3b, 0xf7, 0x44, 0x47, 0xdf, 0x73, 0x44,
0xff, 0xd3, 0x23, 0x33, 0x73, 0x23, 0x33, 0x33, 0x22, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x3f,
0x44, 0x4f, 0xff, 0x74, 0x44, 0x7f, 0xff, 0x34, 0x44, 0xcf, 0xfc, 0x34, 0x43, 0xff, 0xf7, 0x34,
0x3b, 0xff, 0xf2, 0x43, 0x4f, 0xff, 0xc3, 0x33, 0xff, 0xff, 0x43, 0x33, 0xff, 0xff, 0x13, 0x33,
0x44, 0x4e, 0xc4, 0x44, 0x44, 0x4f, 0x44, 0x44, 0x44, 0xbf, 0x34, 0x44, 0x33, 0xeb, 0x34, 0x44,
0x34, 0xf3, 0x33, 0x3b, 0x3b, 0xe2, 0x33, 0x3d, 0x2f, 0xb3, 0x33, 0x3f, 0x4f, 0x23, 0x23, 0xbf,
0x45, 0x44, 0x44, 0x45, 0x44, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, 0x44, 0x43, 0x33, 0x33, 0x33,
0xbb, 0xbb, 0xbb, 0xbb, 0xff, 0xff, 0xff, 0xff, 0x12, 0x11, 0x11, 0x11, 0x22, 0x32, 0x32, 0x32,
0x44, 0x53, 0xfb, 0x44, 0x44, 0x44, 0xbf, 0x44, 0x44, 0x44, 0x3f, 0x54, 0x33, 0x33, 0x2d, 0xc3,
0xbb, 0xbb, 0xbc, 0xf3, 0xff, 0xff, 0xff, 0xf7, 0x11, 0x11, 0x11, 0x12, 0x32, 0x32, 0x32, 0x33,
0x53, 0xff, 0x74, 0x44, 0x44, 0xbf, 0x74, 0x44, 0x44, 0x4f, 0x74, 0x44, 0x34, 0x3f, 0x74, 0x44,
0x43, 0x3b, 0x73, 0x34, 0x33, 0x33, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x4e, 0xc4, 0x44, 0x4c, 0x4e, 0xc4, 0x44, 0x4c, 0x3e, 0xc4, 0x34, 0x4c, 0x3e, 0xc3, 0x44, 0x3b,
0x3e, 0xc3, 0x33, 0x3b, 0x3e, 0xc3, 0x33, 0x3b, 0x2e, 0xb3, 0x33, 0x3b, 0x2e, 0xb2, 0x33, 0x2b,
0xf5, 0x44, 0x44, 0xbf, 0xfd, 0x44, 0x44, 0x3f, 0xff, 0x74, 0x44, 0x47, 0xff, 0xf3, 0x44, 0x42,
0xff, 0xfb, 0x33, 0x33, 0xff, 0xff, 0x33, 0x33, 0xff, 0xff, 0xc2, 0x33, 0xff, 0xdf, 0xf4, 0x33,
0x74, 0x45, 0x4b, 0xff, 0xf4, 0x44, 0x43, 0xff, 0xfb, 0x44, 0x43, 0x7f, 0xdf, 0x34, 0x34, 0x2e,
0x3f, 0xc3, 0x43, 0x34, 0x2c, 0xf4, 0x33, 0x32, 0x32, 0xfd, 0x23, 0x33, 0x22, 0x7f, 0x73, 0x33,
0xf4, 0x44, 0x4b, 0xf4, 0xf4, 0x44, 0x47, 0xf4, 0xf4, 0x44, 0x43, 0xfb, 0xf7, 0x44, 0x43, 0xbf,
0xfc, 0x33, 0x33, 0x2b, 0xdf, 0x33, 0x33, 0x32, 0x3f, 0xb2, 0x33, 0x33, 0x2c, 0xf7, 0x23, 0x33,
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x44, 0x43, 0x44, 0xb4, 0x33, 0x33, 0x33,
0xff, 0xff, 0xff, 0xff, 0x24, 0x77, 0x77, 0x77, 0x32, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33,
0x44, 0x44, 0xfc, 0x44, 0x44, 0x44, 0xfb, 0x44, 0x44, 0x37, 0xf4, 0x34, 0x34, 0xbf, 0xc3, 0x44,
0xff, 0xfb, 0x23, 0x43, 0x74, 0x22, 0x33, 0x33, 0x23, 0x23, 0x33, 0x33, 0x33, 0x33, 0x23, 0x24,
0x44, 0xee, 0x44, 0x44, 0x44, 0xff, 0x44, 0x44, 0x44, 0xff, 0x44, 0x44, 0x47, 0xff, 0x74, 0x44,
0x3b, 0xff, 0xb3, 0x33, 0x3f, 0xff, 0xf3, 0x33, 0x7f, 0xff, 0xfb, 0x33, 0xff, 0xee, 0xff, 0x42,
0xce, 0x44, 0x44, 0x44, 0xbf, 0x34, 0x44, 0x44, 0x4f, 0x73, 0x44, 0x44, 0x3c, 0xfb, 0x43, 0x33,
0x32, 0xbf, 0xff, 0xff, 0x33, 0x22, 0x47, 0x77, 0x33, 0x33, 0x22, 0x22, 0x32, 0x33, 0x33, 0x33,
0x44, 0x44, 0x44, 0x4f, 0x44, 0x44, 0x44, 0x4f, 0x34, 0x44, 0x43, 0xbf, 0x33, 0x33, 0x4b, 0xfb,
0xff, 0xff, 0xff, 0xb2, 0x77, 0x77, 0x42, 0x23, 0x22, 0x22, 0x23, 0x33, 0x33, 0x33, 0x33, 0x32,
0xb4, 0x44, 0x4f, 0xfc, 0x74, 0x44, 0x4f, 0xfc, 0x34, 0x44, 0x4f, 0xfb, 0x33, 0x44, 0x7f, 0xf7,
0x44, 0x33, 0xcf, 0xf4, 0x33, 0x33, 0xff, 0xd3, 0x33, 0x2b, 0xff, 0xb1, 0x32, 0x7f, 0xff, 0x30,
0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xcf, 0xf2, 0x33, 0x33, 0xcf, 0xf1, 0x11, 0x11, 0xcf, 0xfd, 0xdd, 0xdd, 0xcf, 0xff, 0xff, 0xff,
0xbd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x33, 0x33, 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x32, 0x22, 0x17, 0xff, 0x11, 0x3b, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xfb, 0x14,
0xdc, 0xb4, 0x11, 0x1b, 0x11, 0x10, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xfb, 0x23, 0x32, 0xef, 0xf2, 0x11, 0x11, 0xef, 0xfd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xce, 0x13, 0x32, 0xdf, 0xf7, 0x11, 0x12, 0xff, 0xfd, 0xdd, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x33, 0x33, 0x33, 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x33, 0x33, 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x33, 0x33, 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1e, 0xb2, 0x33, 0x2b, 0x1e, 0xb1, 0x11, 0x1b, 0xdf, 0xed, 0xdd, 0xde, 0xff, 0xff, 0xff, 0xff,
0xee, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x3f, 0xfe, 0x13, 0xff, 0x1c, 0xff, 0x71, 0xff, 0x22, 0xff, 0xfd, 0xff, 0x21, 0x7f, 0xff,
0xde, 0x20, 0x1d, 0xdd, 0x11, 0x20, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x1f, 0xf1, 0x33, 0x11, 0x13, 0xfb, 0x11, 0xdd, 0xdd, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0xff, 0x71, 0x22, 0x11, 0x7f, 0xfe, 0x73, 0xdd, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdd, 0xdb, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x33, 0x33, 0x33, 0x11, 0x11, 0x11, 0x11, 0xfe, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff,
0xcd, 0xdd, 0xdd, 0xdd, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x23, 0x21, 0x7f, 0x11, 0x13, 0x7e, 0xff, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3,
0xdd, 0xcb, 0x41, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x77, 0xff, 0xf7, 0xfb, 0x11, 0xbf, 0xff, 0x71, 0x00, 0x17, 0xff, 0x10, 0x00, 0x01, 0x3b,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x32, 0x33, 0x33, 0xe7, 0x31, 0x11, 0x11, 0xff, 0xff, 0xed, 0xdd, 0xff, 0xff, 0xff, 0xff,
0x14, 0xbc, 0xdd, 0xdd, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x32, 0x22, 0x11, 0x11, 0x11, 0x37, 0xdd, 0xdd, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff,
0xdd, 0xdd, 0xdc, 0xb4, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0xff, 0xf7, 0x10, 0xef, 0xff, 0x72, 0x00, 0xff, 0xf7, 0x10, 0x00, 0xfb, 0x21, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif

View file

@ -13,6 +13,7 @@
#define SMPC_H_
/******************************************************************************/
#define SMPC_BASE 0x20100000
@ -89,12 +90,55 @@
#define RESDISA 0x1a
/******************************************************************************/
#define SCU_BASE 0x25FE0000
/* SCU A-BUS */
#define ASR0 REG(SCU_BASE+0xb0)
#define ASR1 REG(SCU_BASE+0xb4)
#define AREF REG(SCU_BASE+0xb8)
/* SCU DMA */
#define SCU_DMA_BASE (SCU_BASE+0x0000)
#define SD0R REG(SCU_BASE+0x00)
#define SD0W REG(SCU_BASE+0x04)
#define SD0C REG(SCU_BASE+0x08)
#define SD0AD REG(SCU_BASE+0x0c)
#define SD0EN REG(SCU_BASE+0x10)
#define SD0MD REG(SCU_BASE+0x14)
#define SD1R REG(SCU_BASE+0x20)
#define SD1W REG(SCU_BASE+0x24)
#define SD1C REG(SCU_BASE+0x28)
#define SD1AD REG(SCU_BASE+0x2c)
#define SD1EN REG(SCU_BASE+0x30)
#define SD1MD REG(SCU_BASE+0x34)
#define SD2R REG(SCU_BASE+0x40)
#define SD2W REG(SCU_BASE+0x44)
#define SD2C REG(SCU_BASE+0x48)
#define SD2AD REG(SCU_BASE+0x4c)
#define SD2EN REG(SCU_BASE+0x50)
#define SD2MD REG(SCU_BASE+0x54)
#define SDSTOP REG(SCU_BASE+0x60)
#define SDSTAT REG(SCU_BASE+0x7c)
typedef struct {
u32 src;
u32 dst;
u32 count;
u32 addv;
u32 enable;
u32 mode;
u32 unk_18;
u32 unk_1c;
}SCUDMA_REG;
#define SCUDMA ((volatile SCUDMA_REG *)(SCU_DMA_BASE))
/******************************************************************************/
/* CPU SCI port */
#define SMR REG8(0xfffffe00)
#define BRR REG8(0xfffffe01)
@ -129,6 +173,20 @@
#define BDMRB REG (0xffffff74)
#define BRCR REG16(0xffffff78)
/* CPU DMAC */
#define SAR0 REG (0xffffff80)
#define DAR0 REG (0xffffff84)
#define TCR0 REG (0xffffff88)
#define CHCR0 REG (0xffffff8c)
#define VCRDMA0 REG (0xffffffa0)
#define DRCR0 REG8(0xffffff71)
#define SAR1 REG (0xffffff90)
#define DAR1 REG (0xffffff94)
#define TCR1 REG (0xffffff98)
#define CHCR1 REG (0xffffff9c)
#define VCRDMA1 REG (0xffffffa8)
#define DRCR1 REG8(0xffffff72)
#define DMAOR REG (0xffffffb0)

View file

@ -7,15 +7,14 @@
.section .sysid
hwid: .ascii "SEGA SEGASATURN "
makerid: .ascii "ANDERS MONTONEN "
produm: .ascii "ANTIME-001"
makerid: .ascii "TPU "
produm: .ascii "T-7605781 "
version: .ascii "V1.003"
reldat: .ascii "20120610"
reldat: .ascii "20230214"
devinfo: .ascii "R 2 "
area: .ascii "JTUE "
.ascii " "
area: .ascii "JTUEABLK "
periph: .ascii "J "
title: .ascii " "
title: .ascii "SAROO firm "
.ascii " "
.ascii " "
.ascii " "
@ -38,4 +37,7 @@ firstsize: .long 0
.incbin "sega/sys_aret.bin"
.incbin "sega/sys_areu.bin"
.incbin "sega/sys_aree.bin"
.incbin "sega/sys_init.bin"
.incbin "sega/sys_area.bin"
.incbin "sega/sys_areb.bin"
.incbin "sega/sys_arel.bin"
.incbin "sega/sys_arek.bin"

View file

@ -1,7 +1,7 @@
# SAROO config file
# 可用配置:
# lang_id=x
# 选择菜单语言: 0:中文 1:EN 2:PTBR 3:JA 4:FR 5:RU 6:繁中 7:de 8:es 9:IT
# 选择菜单语言: 0:中文 1:EN 2:PTBR 3:JA 4:FR 5:RU 6:繁中 7:DE 8:ES 9:IT 10:PL 11:SWE
# debug=xxxxxxxx
# 各种调试选项
# auto_update:

13790
tools/bdfont/bdf/helvR14.bdf Normal file

File diff suppressed because it is too large Load diff

16201
tools/bdfont/bdf/timR14.bdf Normal file

File diff suppressed because it is too large Load diff

View file

@ -71,7 +71,7 @@ CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "-1"
CHARSET_COLLECTIONS "ASCII ISO8859-5 GB2312.1980 BIG5-0 KSC5601.1989-0 JISX0208.1997 ISO10646-1"
ENDPROPERTIES
CHARS 22852
CHARS 22857
STARTCHAR nounicode-3-1-c
ENCODING 12
SWIDTH 333 0
@ -13264,6 +13264,40 @@ BITMAP
0200
0100
ENDCHAR
STARTCHAR uni3006
ENCODING 12294
SWIDTH 1000 0
DWIDTH 14 0
BBX 8 8 2 1
BITMAP
01
22
74
58
98
A4
C0
80
ENDCHAR
STARTCHAR uni3007
ENCODING 12295
SWIDTH 1000 0
DWIDTH 14 0
BBX 12 12 1 -1
BITMAP
0F00
30C0
4020
4020
8010
8010
8010
8010
4020
4020
30C0
0F00
ENDCHAR
STARTCHAR U_3008
ENCODING 12296
SWIDTH 1000 0
@ -13553,6 +13587,17 @@ FC
44
FC
ENDCHAR
STARTCHAR uni301C
ENCODING 12316
SWIDTH 1000 0
DWIDTH 14 0
BBX 12 4 1 3
BITMAP
3800
4410
8220
01C0
ENDCHAR
STARTCHAR U_301D
ENCODING 12317
SWIDTH 1000 0
@ -16612,6 +16657,24 @@ BITMAP
10
20
ENDCHAR
STARTCHAR uni30FB
ENCODING 12539
SWIDTH 1000 0
DWIDTH 14 0
BBX 3 3 6 4
BITMAP
40
E0
40
ENDCHAR
STARTCHAR uni30FC
ENCODING 12540
SWIDTH 1000 0
DWIDTH 14 0
BBX 9 1 3 5
BITMAP
FF80
ENDCHAR
STARTCHAR U_3105
ENCODING 12549
SWIDTH 1000 0

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,4 @@
0000-017f
0180-024f
0370-03ff
0400-04ff

View file

@ -1,4 +1,4 @@
#!/bin/sh
./bdfont cbdf/timR14c.bdf -l latin.txt -h font_latin.h font_latin
./bdfont cbdf/helvR14c.bdf -l latin.txt -h font_latin.h font_latin
./bdfont bdf/wqy13px.bdf -l cjk.txt -adj 1 -c font_cjk.bin

View file

@ -33,27 +33,29 @@ u32 get_be16(void *p);
void put_be32(void *p, u32 v);
void put_be16(void *p, u32 v);
u32 crc32b(u8 *data, int size);
void set_bitmap(u8 *bmp, int index, int val);
SAVEINFO *load_saveraw(char *save_name);
void bup_flush(void);
int sr_bup_init(u8 *buf);
int sr_bup_list(int slot_id);
int sr_bup_export(int slot_id, int save_id);
int sr_bup_export(int slot_id, int save_id, int exp_type);
int sr_bup_import(int slot_id, int save_id, char *save_name);
int sr_bup_delete(int slot_id, int save_id);
int sr_bup_create(char *game_id);
int ss_bup_init(u8 *buf);
int ss_bup_list(int slot_id);
int ss_bup_export(int slot_id, int save_id);
int ss_bup_export(int slot_id, int save_id, int exp_type);
int ss_bup_import(int slot_id, int save_id, char *save_name);
int ss_bup_delete(int slot_id, int save_id);
int ss_bup_create(char *game_id);
int sr_mems_init(u8 *buf);
int sr_mems_list(int slot_id);
int sr_mems_export(int slot_id, int save_id);
int sr_mems_export(int slot_id, int save_id, int exp_type);
int sr_mems_import(int slot_id, int save_id, char *save_name);
int sr_mems_delete(int slot_id, int save_id);
int sr_mems_create(char *game_id);

119
tools/savetool/bup_format.h Normal file
View file

@ -0,0 +1,119 @@
/*
* bup_header.h - structure definition for the .BUP file header used
* by various Sega Saturn tools.
*
* Format developed by Cafe-Alpha (https://segaxtreme.net/threads/save-game-metadata-questions.24625/post-178534)
*
*/
/** .BUP extension is required to work wih PS Kai */
#define BUP_EXTENSION ".BUP"
/** The BUP header structure (sizeof(vmem_bup_header_t)) is exactly 64 bytes */
#define BUP_HEADER_SIZE 64
/** BUP header magic */
#define VMEM_MAGIC_STRING_LEN 4
#define VMEM_MAGIC_STRING "Vmem"
/** Max backup filename length */
#define JO_BACKUP_MAX_FILENAME_LENGTH (12)
/** Max backup file comment length */
#define JO_BACKUP_MAX_COMMENT_LENGTH (10)
/**
* Backup file metadata information. Taken from Jo Engine.
**/
typedef struct _jo_backup_file
{
unsigned char filename[JO_BACKUP_MAX_FILENAME_LENGTH];
unsigned char comment[JO_BACKUP_MAX_COMMENT_LENGTH + 1];
unsigned char language; // jo_backup_language
unsigned int date;
unsigned int datasize;
unsigned short blocksize;
unsigned short padding;
} jo_backup_file;
typedef struct _jo_backup_date {
unsigned char year; // year - 1980
unsigned char month;
unsigned char day;
unsigned char time;
unsigned char min;
unsigned char week;
} jo_backup_date;
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
/**
* Vmem usage statistics structure.
* Statistics are reset on each vmem session, ie when Saturn is reset,
* or when game calls BUP_Init function.
**/
typedef struct _vmem_bup_stats_t
{
/* Number of times BUP_Dir function is called. */
unsigned char dir_cnt;
/* Number of times BUP_Read function is called. */
unsigned char read_cnt;
/* Number of times BUP_Write function is called. */
unsigned char write_cnt;
/* Number of times BUP_Verify function is called. */
unsigned char verify_cnt;
} vmem_bup_stats_t;
/**
* Backup data header. Multibyte values are stored as big-endian.
**/
typedef struct _vmem_bup_header_t
{
/* Magic string.
* Used in order to verify that file is in vmem format.
*/
char magic[VMEM_MAGIC_STRING_LEN];
/* Save ID.
* "Unique" ID for each save data file, the higher, the most recent.
*/
unsigned int save_id;
/* Vmem usage statistics. */
vmem_bup_stats_t stats;
/* Unused, kept for future use. */
char unused1[8 - sizeof(vmem_bup_stats_t)];
/* Backup Data Informations Record (34 bytes + 2 padding bytes). */
jo_backup_file dir;
/* Date stamp, in Saturn's BUP library format.
* Used in order to verify which save data is the most
* recent one when rebuilding index data.
* Note #1 : this information is already present in BupDir structure,
* but games are setting it, so it may be incorrect (typically, set
* to zero).
* Note #2 : this date information is the date when Pseudo Saturn Kai
* last started, not the time the save was saved, so if information in
* dir structure is available, it is more accurate.
*/
unsigned int date;
/* Unused, kept for future use. */
char unused2[8];
} vmem_bup_header_t;
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif

View file

@ -3,6 +3,7 @@
#include "stdlib.h"
#include "string.h"
#include "bup.h"
#include "bup_format.h"
/******************************************************************************/
@ -98,22 +99,61 @@ void set_bitmap(u8 *bmp, int index, int val)
u8 save_buf[0x100000];
static SAVEINFO saveinfo;
/* This is the basic CRC-32 calculation with some optimization but no table lookup. */
u32 crc32b(u8 *data, int size)
{
int j;
u32 crc = 0xFFFFFFFF;
while (size--){
crc ^= *data++; // XOR with next byte.
for (j=0; j<8; j++){ // Do eight times.
crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
}
}
return ~crc;
}
static void load_savebup(SAVEINFO *sinfo, const u8 *fbuf, int fsize)
{
vmem_bup_header_t *bup_header = (vmem_bup_header_t*)fbuf;
memset(sinfo, 0, sizeof(SAVEINFO));
memcpy(sinfo->file_name, bup_header->dir.filename, 11);
memcpy(sinfo->comment, bup_header->dir.comment, 10);
sinfo->data_size = bup_header->dir.datasize;
sinfo->date = bup_header->dir.date;
sinfo->language = bup_header->dir.language;
memcpy(save_buf, fbuf+BUP_HEADER_SIZE, fsize-BUP_HEADER_SIZE);
sinfo->dbuf = save_buf;
}
SAVEINFO *load_saveraw(char *save_name)
{
SAVEINFO *sinfo = &saveinfo;
u8 *fbuf;
int fsize;
u32 crc;
fbuf = load_file(save_name, &fsize);
if(fbuf==NULL){
printf("Faield to load file %s!\n", save_name);
return NULL;
}
if(strcmp((char*)fbuf, "SSAVERAW")){
printf("%s: Not a SSAVERAW file!\n", save_name);
if(strcmp((char*)fbuf, "SSAVERAW") && memcmp(fbuf, VMEM_MAGIC_STRING, VMEM_MAGIC_STRING_LEN)){
printf("%s: Not a supported Saturn save file! (%s/%s)\n", save_name, "SSAVERAW", VMEM_MAGIC_STRING);
return NULL;
}
// check if it's a Vmem save file, and load the data
if(memcmp(fbuf, VMEM_MAGIC_STRING, VMEM_MAGIC_STRING_LEN)==0 && fsize>BUP_HEADER_SIZE){
load_savebup(sinfo, fbuf, fsize);
return sinfo;
}
memset(sinfo, 0, sizeof(SAVEINFO));
memcpy(sinfo->file_name, fbuf+0x10, 11);
memcpy(sinfo->comment, fbuf+0x20, 10);
@ -123,6 +163,12 @@ SAVEINFO *load_saveraw(char *save_name)
memcpy(save_buf, fbuf+0x40, fsize-0x40);
sinfo->dbuf = save_buf;
crc = get_be32(fbuf+0x0c);
if (crc && crc != crc32b(fbuf+0x10, fsize-0x10)){
printf("Warning: CRC32 mismatch for %s!\n", save_name);
}
return sinfo;
}
@ -146,7 +192,7 @@ void bup_flush(void)
int bup_create(char *game_id)
{
int retv;
int retv=-1;
if(bup_type==0){
retv = sr_bup_create(game_id);
@ -167,7 +213,7 @@ int bup_create(char *game_id)
int bup_import(int slot_id, int save_id, char *save_name)
{
int retv;
int retv=-1;
if(bup_type==0){
retv = sr_bup_import(slot_id, save_id, save_name);
@ -186,7 +232,7 @@ int bup_import(int slot_id, int save_id, char *save_name)
int bup_delete(int slot_id, int save_id)
{
int retv;
int retv=-1;
if(bup_type==0){
retv = sr_bup_delete(slot_id, save_id);
@ -203,14 +249,14 @@ int bup_delete(int slot_id, int save_id)
}
int bup_export(int slot_id, int save_id)
int bup_export(int slot_id, int save_id, int exp_type)
{
if(bup_type==0){
return sr_bup_export(slot_id, save_id);
return sr_bup_export(slot_id, save_id, exp_type);
}else if(bup_type==1){
return ss_bup_export(slot_id, save_id);
return ss_bup_export(slot_id, save_id, exp_type);
}else if(bup_type==2){
return sr_mems_export(slot_id, save_id);
return sr_mems_export(slot_id, save_id, exp_type);
}
return -1;
@ -265,6 +311,7 @@ int main(int argc, char *argv[])
{
int slot_id = -1;
int save_id = -1;
int exp_type = 0;
int create = 0;
int import = 0;
int delete = 0;
@ -280,6 +327,7 @@ int main(int argc, char *argv[])
printf(" -t n Select save slot(for SAROO save).\n");
printf(" -c \"gameid\" New save slot(for SAROO save).\n");
printf(" -s n Select and Export(without -i/-d) save.\n");
printf(" -x n Select and Export save as .BUP format.\n");
printf(" -i [file] Import save.\n");
printf(" -d Delete save.\n");
printf(" List save.\n");
@ -297,6 +345,8 @@ int main(int argc, char *argv[])
slot_id = atoi(argv[p+1]);
p += 1;
break;
case 'x':
exp_type = 1;
case 's':
if(p+1==argc)
goto _invalid_params;
@ -345,7 +395,7 @@ _invalid_params:
retv = bup_load(bup_name);
if(retv<0){
printf("Faield to load save file!\n");
printf("Failed to load save file!\n");
return retv;
}
@ -356,7 +406,7 @@ _invalid_params:
}else if(delete){
retv = bup_delete(slot_id, save_id);
}else if(save_id>=0){
retv = bup_export(slot_id, save_id);
retv = bup_export(slot_id, save_id, exp_type);
}else{
retv = bup_list(slot_id);
}

View file

@ -3,6 +3,7 @@
#include "stdlib.h"
#include "string.h"
#include "bup.h"
#include "bup_format.h"
/******************************************************************************/
@ -179,7 +180,7 @@ static int sr_bup_select(int slot_id)
/******************************************************************************/
int sr_bup_export(int slot_id, int save_id)
int sr_bup_export(int slot_id, int save_id, int exp_type)
{
int block, i;
u8 *bp;
@ -205,7 +206,24 @@ int sr_bup_export(int slot_id, int save_id)
char fname[16];
int fsize = get_be32(save_buf+0x1c);
sprintf(fname, "%s.bin", save_buf+0x10);
put_be32(save_buf+0x0c, crc32b(save_buf+0x10, fsize+0x30));
sprintf(fname, "%s%s", save_buf+0x10, exp_type ? BUP_EXTENSION : ".SRO");
// if Export format is .BUP, set new header
if (exp_type==1){
vmem_bup_header_t bup_header = {0};
memcpy(bup_header.magic, VMEM_MAGIC_STRING, VMEM_MAGIC_STRING_LEN);
memcpy(bup_header.dir.filename, bp, 11);
memcpy(bup_header.dir.comment, bp+0x10, 10);
memcpy(&bup_header.dir.date, bp+0x1c, 4);
memcpy(&bup_header.dir.datasize, bp+0x0c, 4);
memcpy(&bup_header.date, bp+0x1c, 4);
bup_header.dir.language = bp[0x1b];
memcpy(save_buf, &bup_header, BUP_HEADER_SIZE);
}
write_file(fname, save_buf, fsize+0x40);
printf("Export Save_%d: %s\n", i, fname);

View file

@ -3,6 +3,7 @@
#include "stdlib.h"
#include "string.h"
#include "bup.h"
#include "bup_format.h"
/******************************************************************************/
@ -94,7 +95,7 @@ static int access_data(int block, u8 *data, int type)
/******************************************************************************/
int sr_mems_export(int slot_id, int save_id)
int sr_mems_export(int slot_id, int save_id, int exp_type)
{
int block, i, index;
u8 *bp;
@ -121,7 +122,24 @@ int sr_mems_export(int slot_id, int save_id)
char fname[16];
int fsize = get_be32(save_buf+0x1c);
sprintf(fname, "%s.bin", save_buf+0x10);
put_be32(save_buf+0x0c, crc32b(save_buf+0x10, fsize+0x30));
sprintf(fname, "%s%s", save_buf+0x10, exp_type ? BUP_EXTENSION : ".SRO");
// if Export format is .BUP, set new header
if (exp_type==1){
vmem_bup_header_t bup_header = {0};
memcpy(bup_header.magic, VMEM_MAGIC_STRING, VMEM_MAGIC_STRING_LEN);
memcpy(bup_header.dir.filename, bp, 11);
memcpy(bup_header.dir.comment, bp+0x10, 10);
memcpy(&bup_header.dir.date, bp+0x1c, 4);
memcpy(&bup_header.dir.datasize, bp+0x0c, 4);
memcpy(&bup_header.date, bp+0x1c, 4);
bup_header.dir.language = bp[0x1b];
memcpy(save_buf, &bup_header, BUP_HEADER_SIZE);
}
write_file(fname, save_buf, fsize+0x40);
printf("Export Save_%d: %s\n", index, fname);

View file

@ -3,6 +3,7 @@
#include "stdlib.h"
#include "string.h"
#include "bup.h"
#include "bup_format.h"
/******************************************************************************/
@ -135,7 +136,7 @@ static void scan_save(BUPINFO *binfo)
/******************************************************************************/
int ss_bup_export(int slot_id, int index)
int ss_bup_export(int slot_id, int index, int exp_type)
{
BUPINFO *binfo = GET_BUP_INFO();
int block, i;
@ -160,7 +161,24 @@ int ss_bup_export(int slot_id, int index)
char fname[16];
int fsize = get_be32(save_buf+0x1c);
sprintf(fname, "%s.bin", save_buf+0x10);
put_be32(save_buf+0x0c, crc32b(save_buf+0x10, fsize+0x30));
sprintf(fname, "%s%s", save_buf+0x10, exp_type ? BUP_EXTENSION : ".SRO");
// if Export format is .BUP, set new header
if (exp_type==1){
vmem_bup_header_t bup_header = {0};
memcpy(bup_header.magic, VMEM_MAGIC_STRING, VMEM_MAGIC_STRING_LEN);
memcpy(bup_header.dir.filename, bp+4, 11);
memcpy(bup_header.dir.comment, bp+0x10, 10);
memcpy(&bup_header.dir.date, bp+0x1a, 4);
memcpy(&bup_header.dir.datasize, bp+0x1e, 4);
memcpy(&bup_header.date, bp+0x1a, 4);
bup_header.dir.language = bp[0x0f];
memcpy(save_buf, &bup_header, BUP_HEADER_SIZE);
}
write_file(fname, save_buf, fsize+0x40);
printf("Export Save_%d: %s\n", index, fname);