1. MCU端开机内存测试功能

2. MCU端固件自动更新
3. 支持启动光盘游戏
This commit is contained in:
tpu 2023-10-31 12:59:30 +08:00
parent 4252c5a813
commit 19b2e5c180
22 changed files with 783 additions and 699 deletions

View file

@ -225,10 +225,10 @@ int flash_update(int check)
return -1; return -1;
} }
fsize = f_size(&fp); fsize = f_size(&fp);
printk("Found firm file.\n");
printk(" Size %08x\n", fsize);
if(check){ if(check){
printk("Found firm file.\n");
printk(" Size %08x\n", fsize);
f_close(&fp); f_close(&fp);
return 0; return 0;
} }
@ -236,16 +236,16 @@ int flash_update(int check)
u32 rv; u32 rv;
f_read(&fp, fbuf, fsize, &rv); f_read(&fp, fbuf, fsize, &rv);
f_close(&fp);
int key = disable_irq();
disable_irq();
int firm_addr = 0x08000000; int firm_addr = 0x08000000;
_puts("erase ...\n"); _puts("erase ...\n");
retv = flash_erase(firm_addr); retv = flash_erase(firm_addr);
if(retv){ if(retv){
restore_irq(key);
_puts(" faile!\n"); _puts(" faile!\n");
f_close(&fp);
return -2; return -2;
} }
@ -253,14 +253,16 @@ int flash_update(int check)
for(i=0; i<fsize; i+=32){ for(i=0; i<fsize; i+=32){
retv = flash_write32(firm_addr+i, fbuf+i); retv = flash_write32(firm_addr+i, fbuf+i);
if(retv){ if(retv){
restore_irq(key);
_puts(" faile!\n"); _puts(" faile!\n");
f_close(&fp);
return -3; return -3;
} }
} }
f_close(&fp); restore_irq(key);
_puts("done.\n");
printk("MCU update OK!\n");
f_unlink("/SAROO/update/ssmaster.bin");
return 0; return 0;
} }
@ -317,10 +319,13 @@ void main_task(void *arg)
static osSemaphoreId_t sem_led; static osSemaphoreId_t sem_led;
static int led_ev = 0; static int led_ev = 0;
static int loop = 0;
void led_event(int ev) void led_event(int ev)
{ {
led_ev = ev; led_ev = ev;
if(ev==0)
loop = 0;
osSemaphoreRelease(sem_led); osSemaphoreRelease(sem_led);
} }
@ -331,7 +336,6 @@ void led_task(void *arg)
int freq; int freq;
int times; int times;
int lock; int lock;
int loop = 0;
sem_led = osSemaphoreNew(1, 0, NULL); sem_led = osSemaphoreNew(1, 0, NULL);
@ -373,7 +377,7 @@ int main(void)
osThreadNew(main_task, NULL, &attr); osThreadNew(main_task, NULL, &attr);
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
attr.priority = osPriorityLow; attr.priority = osPriorityHigh;
osThreadNew(led_task, NULL, &attr); osThreadNew(led_task, NULL, &attr);
osKernelStart(); osKernelStart();

View file

@ -510,6 +510,7 @@ int sdio_init(void)
SDIO->MASK = 0; SDIO->MASK = 0;
SDIO->ICR = 0x1fe00fff; SDIO->ICR = 0x1fe00fff;
SDIO->CLKCR = 0; SDIO->CLKCR = 0;
SDIO->CLKCR = 1<<16;
sd_rca = 0; sd_rca = 0;
cmd_sem = osSemaphoreNew(1, 0, NULL); cmd_sem = osSemaphoreNew(1, 0, NULL);

View file

@ -199,40 +199,45 @@ static u16 mksum(u32 addr)
} }
int mem_test(void) int mem_test(u32 addr, int size)
{ {
u32 addr0 = 0x61400000;
u16 rd, sum; u16 rd, sum;
int i, size=0x00100000; int i, ecnt=0;
printk("Memory test at %08x ...", addr);
size /= 2;
for(i=0; i<size; i++){ for(i=0; i<size; i++){
*(u16*)(addr0) = mksum(addr0); *(u16*)(addr) = mksum(addr);
addr0 += 2; addr += 2;
} }
for(i=0; i<size; i++){ for(i=0; i<size; i++){
addr0 -= 2; addr -= 2;
sum = mksum(addr0); sum = mksum(addr);
rd = *(u16*)(addr0); rd = *(u16*)(addr);
if(sum!=rd){ if(sum!=rd){
printk("Mismatch0 at %08x! read=%08x calc=%08x\n", addr0, rd, sum); printk("\nMismatch0 at %08x! read=%08x calc=%08x\n", addr, rd, sum);
return -1; ecnt += 1;
} }
*(u16*)(addr0) = ~sum; *(u16*)(addr) = ~sum;
} }
for(i=0; i<size; i++){ for(i=0; i<size; i++){
sum = ~mksum(addr0); sum = ~mksum(addr);
rd = *(u16*)(addr0); rd = *(u16*)(addr);
if(sum!=rd){ if(sum!=rd){
printk("Mismatch2 at %08x! read=%08x calc=%08x\n", addr0, rd, sum); printk("\nMismatch2 at %08x! read=%08x calc=%08x\n", addr, rd, sum);
return -3; ecnt += 1;
} }
addr0 += 2; addr += 2;
} }
return 0; if(ecnt==0)
printk(" OK!\n\n");
return ecnt;
} }
/******************************************************************************/ /******************************************************************************/
@ -293,8 +298,15 @@ void simple_shell(void)
} }
CMD(mmt){ CMD(mmt){
mem_test(); u32 addr = 0x61000000;
int size = 0x00100000;
if(argc==2){
addr = arg[0];
size = arg[1];
}
mem_test(addr, size);
} }
CMD(memset){ CMD(memset){
if(argc>=3){ if(argc>=3){
memset((void*)arg[0], arg[1], arg[2]); memset((void*)arg[0], arg[1], arg[2]);

View file

@ -244,12 +244,11 @@ int fpga_update(int check)
printk("No FPGA config file.\n"); printk("No FPGA config file.\n");
return -1; return -1;
} }
fsize = f_size(&fp); fsize = f_size(&fp);
printk("Found FPGA config file.\n");
printk(" Size %08x\n", fsize);
if(check){ if(check){
printk("Found FPGA config file.\n");
printk(" Size %08x\n", fsize);
f_close(&fp); f_close(&fp);
return 0; return 0;
} }
@ -272,6 +271,7 @@ int fpga_update(int check)
f_close(&fp); f_close(&fp);
printk("FPGA update OK!\n"); printk("FPGA update OK!\n");
f_unlink("/SAROO/update/SSMaster.rbf");
return 0; return 0;
} }

View file

@ -108,6 +108,7 @@
#define SSCMD_FILEWR 0x0007 #define SSCMD_FILEWR 0x0007
#define SSCMD_LISTBIN 0x0008 #define SSCMD_LISTBIN 0x0008
#define SSCMD_SSAVE 0x0009 #define SSCMD_SSAVE 0x0009
#define SSCMD_LSAVE 0x000a
#define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f) #define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f)
@ -280,6 +281,7 @@ extern int in_isr;
extern int lang_id; extern int lang_id;
extern int debug_flags; extern int debug_flags;
extern int auto_update;
extern int sector_delay; extern int sector_delay;
extern int sector_delay_force; extern int sector_delay_force;
extern int play_delay; extern int play_delay;

View file

@ -15,6 +15,7 @@ int sector_delay = 0;
int sector_delay_force = -1; int sector_delay_force = -1;
int play_delay = 0; int play_delay = 0;
int play_delay_force = -1; int play_delay_force = -1;
int auto_update = 0;
int log_mask = LOG_MASK_DEFAULT; int log_mask = LOG_MASK_DEFAULT;
@ -525,6 +526,12 @@ void ss_cmd_handle(void)
SS_ARG = retv; SS_ARG = retv;
SS_CMD = 0; SS_CMD = 0;
break; break;
case SSCMD_LSAVE:
// 加载指定SAVE
retv = load_savefile((char*)(TMPBUFF_ADDR+0x10));
SS_ARG = retv;
SS_CMD = 0;
break;
default: default:
SSLOG(_INFO, "[SS] unkonw cmd: %04x\n", cmd); SSLOG(_INFO, "[SS] unkonw cmd: %04x\n", cmd);
break; break;
@ -692,10 +699,47 @@ void saturn_config(void)
parse_config("/saroocfg.txt", NULL); parse_config("/saroocfg.txt", NULL);
if(auto_update){
int fp, fl;
fp = fpga_update(1);
fl = flash_update(1);
if(fp==-1 && fl==-1){
// 没有升级文件
led_event(LEDEV_NONE);
}else{
led_event(LEDEV_BUSY);
if(fp==0){
fpga_update(0);
}
if(fl==0){
fl = flash_update(0);
if(fl<-1){
led_event(LEDEV_FILE_ERROR);
return;
}
}
led_event(LEDEV_OK);
return;
}
}
if(debug_flags&0xc0000000){
led_event(LEDEV_BUSY);
int cnt = 0;
while(1){
retv = mem_test(0x61000000, 0x00800000);
if(retv){
led_event(LEDEV_SDRAM_ERROR);
//return;
}
if((debug_flags&0x40000000)==0)
break;
cnt += 1;
printk(" times: %d\n", cnt);
}
led_event(LEDEV_NONE);
}
// 检查是否有bootrom. 如果有,就加载到FPGA中 // 检查是否有bootrom. 如果有,就加载到FPGA中

View file

@ -137,6 +137,7 @@ typedef struct {
CFGARG arg_list [] = { CFGARG arg_list [] = {
{"sector_delay", ARG_DEC, &sector_delay}, {"sector_delay", ARG_DEC, &sector_delay},
{"play_delay", ARG_DEC, &play_delay}, {"play_delay", ARG_DEC, &play_delay},
{"auto_update", ARG_DEC, &auto_update},
{"exmem_", ARG_NON, config_exmem}, {"exmem_", ARG_NON, config_exmem},
{"M_", ARG_NON, config_wrmem}, {"M_", ARG_NON, config_wrmem},
{"lang_id", ARG_DEC, &lang_id}, {"lang_id", ARG_DEC, &lang_id},

View file

@ -30,6 +30,8 @@ u32 get_build_date(void);
void *malloc(uint32_t size); void *malloc(uint32_t size);
void free(void *p); void free(void *p);
void memcpy32(void *dst, void *src, int len); void memcpy32(void *dst, void *src, int len);
int mem_test(u32 addr, int size);
void uart4_init(void); void uart4_init(void);
u8 _getc(void); u8 _getc(void);
@ -66,6 +68,7 @@ int fpga_update(int check);
#define MAKE_LEDEVENT(freq, times, flag) (((flag)<<16) | ((times)<<8) | (freq)) #define MAKE_LEDEVENT(freq, times, flag) (((flag)<<16) | ((times)<<8) | (freq))
#define LEDEV_NONE 0
#define LEDEV_SD_ERROR MAKE_LEDEVENT(10, 10, 2) #define LEDEV_SD_ERROR MAKE_LEDEVENT(10, 10, 2)
#define LEDEV_FPGA_ERROR MAKE_LEDEVENT(10, 20, 2) #define LEDEV_FPGA_ERROR MAKE_LEDEVENT(10, 20, 2)
#define LEDEV_SDRAM_ERROR MAKE_LEDEVENT(15, 8, 2) #define LEDEV_SDRAM_ERROR MAKE_LEDEVENT(15, 8, 2)
@ -73,6 +76,8 @@ int fpga_update(int check);
#define LEDEV_FILE_ERROR MAKE_LEDEVENT(15, 5, 1) #define LEDEV_FILE_ERROR MAKE_LEDEVENT(15, 5, 1)
#define LEDEV_SCFG_ERROR MAKE_LEDEVENT(15, 4, 1) #define LEDEV_SCFG_ERROR MAKE_LEDEVENT(15, 4, 1)
#define LEDEV_CSCT MAKE_LEDEVENT(7, 1, 0) #define LEDEV_CSCT MAKE_LEDEVENT(7, 1, 0)
#define LEDEV_BUSY MAKE_LEDEVENT(50, 1, 1)
#define LEDEV_OK MAKE_LEDEVENT(13, 2, 1)
void led_event(int ev); void led_event(int ev);

View file

@ -157,6 +157,11 @@
<AccSizeX>1</AccSizeX> <AccSizeX>1</AccSizeX>
</Mm> </Mm>
</MemoryWindow1> </MemoryWindow1>
<ScvdPack>
<Filename>d:\Keil_v5\ARM\PACK\ARM\CMSIS\5.7.0\CMSIS\RTOS2\RTX\RTX5.scvd</Filename>
<Type>ARM.CMSIS.5.7.0</Type>
<SubType>1</SubType>
</ScvdPack>
<Tracepoint> <Tracepoint>
<THDelay>0</THDelay> <THDelay>0</THDelay>
</Tracepoint> </Tracepoint>
@ -335,7 +340,7 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>2</GroupNumber> <GroupNumber>2</GroupNumber>
<FileNumber>8</FileNumber> <FileNumber>9</FileNumber>
<FileType>2</FileType> <FileType>2</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -347,7 +352,7 @@
</File> </File>
<File> <File>
<GroupNumber>2</GroupNumber> <GroupNumber>2</GroupNumber>
<FileNumber>9</FileNumber> <FileNumber>10</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -367,7 +372,7 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>10</FileNumber> <FileNumber>11</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -379,7 +384,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>11</FileNumber> <FileNumber>12</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -391,7 +396,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>12</FileNumber> <FileNumber>13</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -403,7 +408,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>13</FileNumber> <FileNumber>14</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -415,7 +420,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>14</FileNumber> <FileNumber>15</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -427,7 +432,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>15</FileNumber> <FileNumber>16</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -439,7 +444,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>16</FileNumber> <FileNumber>17</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -451,7 +456,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>17</FileNumber> <FileNumber>18</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -463,7 +468,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>18</FileNumber> <FileNumber>19</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -475,7 +480,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>19</FileNumber> <FileNumber>20</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -487,7 +492,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>20</FileNumber> <FileNumber>21</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -499,7 +504,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>21</FileNumber> <FileNumber>22</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -511,7 +516,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>22</FileNumber> <FileNumber>23</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -523,7 +528,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>23</FileNumber> <FileNumber>24</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -535,7 +540,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>24</FileNumber> <FileNumber>25</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -547,7 +552,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>25</FileNumber> <FileNumber>26</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -567,7 +572,7 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>26</FileNumber> <FileNumber>27</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -579,7 +584,7 @@
</File> </File>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>27</FileNumber> <FileNumber>28</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -591,7 +596,7 @@
</File> </File>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>28</FileNumber> <FileNumber>29</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -603,7 +608,7 @@
</File> </File>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>29</FileNumber> <FileNumber>30</FileNumber>
<FileType>5</FileType> <FileType>5</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -615,7 +620,7 @@
</File> </File>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>30</FileNumber> <FileNumber>31</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -627,7 +632,7 @@
</File> </File>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>31</FileNumber> <FileNumber>32</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -647,7 +652,7 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>32</FileNumber> <FileNumber>33</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -659,7 +664,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>33</FileNumber> <FileNumber>34</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -671,7 +676,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>34</FileNumber> <FileNumber>35</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -683,7 +688,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>35</FileNumber> <FileNumber>36</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>

View file

@ -22,6 +22,7 @@ OBJ = obj/crt0.o \
obj/sci_shell.o \ obj/sci_shell.o \
obj/ubr_debug.o \ obj/ubr_debug.o \
obj/cdblock.o \ obj/cdblock.o \
obj/game_load.o \
obj/game_patch.o \ obj/game_patch.o \
obj/game_save.o \ obj/game_save.o \
obj/language.o \ obj/language.o \

View file

@ -5,65 +5,13 @@
/**********************************************************/ /**********************************************************/
typedef struct {
u16 cr1;
u16 cr2;
u16 cr3;
u16 cr4;
}CDCMD;
typedef struct {
int fad;
int size;
u8 unit;
u8 gap;
u8 fn;
u8 attr;
}CdcFile;
#define CR1 REG16(0x25890018)
#define CR2 REG16(0x2589001c)
#define CR3 REG16(0x25890020)
#define CR4 REG16(0x25890024)
#define HIRQ REG16(0x25890008)
#define HMSK REG16(0x2589000c)
#define HIRQ_CMOK 0x0001
#define HIRQ_DRDY 0x0002
#define HIRQ_CSCT 0x0004
#define HIRQ_BFUL 0x0008
#define HIRQ_PEND 0x0010
#define HIRQ_DCHG 0x0020
#define HIRQ_ESEL 0x0040
#define HIRQ_EHST 0x0080
#define HIRQ_ECPY 0x0100
#define HIRQ_EFLS 0x0200
#define HIRQ_SCDQ 0x0400
#define STATUS_BUSY 0x00
#define STATUS_PAUSE 0x01
#define STATUS_STANDBY 0x02
#define STATUS_PLAY 0x03
#define STATUS_SEEK 0x04
#define STATUS_SCAN 0x05
#define STATUS_OPEN 0x06
#define STATUS_NODISC 0x07
#define STATUS_RETRY 0x08
#define STATUS_ERROR 0x09
#define STATUS_FATAL 0x0a
#define STATUS_PERIODIC 0x20
#define STATUS_TRANSFER 0x40
#define STATUS_WAIT 0x80
#define STATUS_REJECT 0xff
void clear_hirq(int mask) void clear_hirq(int mask)
{ {
HIRQ = ~mask; HIRQ = ~mask;
} }
int wait_hirq(int mask) int wait_hirq(int mask)
{ {
int i; int i;
@ -77,25 +25,39 @@ int wait_hirq(int mask)
return -3; return -3;
} }
int wait_peri(void)
{
CDCMD resp;
int status;
while(1){ int wait_busy(void)
int i; {
resp.cr1 = CR1; int i;
resp.cr2 = CR2;
resp.cr3 = CR3; for(i=0; i<0x240000; i++){
resp.cr4 = CR4; int cds = (CR1>>8)&0x0f;
printk("STATUS=%04x\n", resp.cr1); if(cds)
status = resp.cr1>>8; return 0;
if(status&STATUS_PERIODIC)
break;
for(i=0; i<100000; i++);
} }
return 0; return -3;
}
void cdc_dump(int count)
{
int hirq_old=-1, cr1_old=-1;
int hirq, cr1, cr2, cr3, cr4;
while(count){
hirq = HIRQ;
cr1 = CR1;
cr2 = CR2;
cr3 = CR3;
cr4 = CR4;
if( (hirq_old != hirq) || (cr1_old != cr1) ){
printk("HIRQ: %04x CR1:%04x CR2:%04x CR3:%04x CR4:%04x\n", hirq, cr1, cr2, cr3, cr4);
hirq_old = hirq;
cr1_old = cr1;
}
count -= 1;
}
} }
@ -145,20 +107,6 @@ int cdc_cmd(int wait, CDCMD *cmd, CDCMD *resp, char *cmdname)
/**********************************************************/ /**********************************************************/
u32 *toc_buf = (u32*)0x06090000;
void show_toc(void)
{
int i;
for(i=0; i<102; i++){
if(toc_buf[i]!=0xffffffff)
printk("TOC %3d: %08x\n", i+1, toc_buf[i]);
}
}
int cdc_get_status(int *status) int cdc_get_status(int *status)
{ {
CDCMD cmd, resp; CDCMD cmd, resp;
@ -568,46 +516,30 @@ int cdc_auth_status(int *status)
} }
void cdc_wait_auth(void)
{
int i, status;
while(1){
for(i=0; i<100000; i++);
cdc_get_status(&status);
if(status!=0xff)
break;
printk("STATUS: %02x HIRQ: %04x\n", status, HIRQ);
}
}
int cdc_auth_device(void) int cdc_auth_device(void)
{ {
CDCMD cmd, resp; CDCMD cmd, resp;
int i, status; int status;
printk("\n\nCD_AUTH ...\n"); printk("\n\nCD_AUTH ... HIRQ=%04x\n", HIRQ);
cmd.cr1 = 0xe000; cmd.cr1 = 0xe000;
cmd.cr2 = 0x0000; cmd.cr2 = 0x0000;
cmd.cr3 = 0x0000; cmd.cr3 = 0x0000;
cmd.cr4 = 0x0000; cmd.cr4 = 0x0000;
cdc_cmd(HIRQ_EFLS, &cmd, &resp, "cdc_auth_device"); clear_hirq(HIRQ_EFLS);
cdc_cmd(0, &cmd, &resp, "cdc_auth_device");
while(1){ while(1){
for(i=0; i<100000; i++); int retv = wait_hirq(HIRQ_EFLS);
cdc_get_status(&status); if(retv==0)
if(status!=0xff)
break; break;
//printk("STATUS: %02x HIRQ: %04x\n", status, HIRQ);
} }
int retv = cdc_auth_status(&status); cdc_auth_status(&status);
printk("AUTH: %02x\n\n", status); printk("AUTH: %02x\n\n", status);
return retv; return status;
} }
/**********************************************************/ /**********************************************************/
@ -701,26 +633,131 @@ int cdc_abort_file(void)
return cdc_cmd(0, &cmd, &resp, "cdc_abort_file"); return cdc_cmd(0, &cmd, &resp, "cdc_abort_file");
} }
void cdc_init(void);
int wait_status(int wait) /**********************************************************/
void cdc_init(void)
{ {
int status; cdc_abort_file();
cdc_cdb_init(0);
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
while(1){ cdc_auth_device();
cdc_get_status(&status); }
printk("STATUS: %02x HIRQ=%04x\n", status, HIRQ);
if(status&0x80){
return -1; int cdc_read_sector(int fad, int size, u8 *buf)
} {
status &= 0x0f; int nsec, retv, status, num;
if(status==wait) num = (size+3)&0xfffffffc;
return 0;
cdc_set_size(0);
cdc_reset_selector(0, 0);
cdc_cddev_connect(0);
cdc_play_fad(0, fad, (size+0x7ff)>>11);
while(num>0){
retv = cdc_get_numsector(0, &nsec);
if(retv<0)
return retv;
if(nsec==0)
continue;
if(num>=2048)
nsec=2048;
else
nsec=num;
cdc_get_del_data(0, 0, 1);
cdc_trans_data(buf, nsec);
cdc_end_trans(&status);
buf += nsec;
num -= nsec;
} }
return -1; return size;
} }
void cdblock_on(int wait)
{
int cdstat;
int cr1, cr2, cr3, cr4;
SS_CTRL = CS0_RAM4M;
smpc_cmd(CDON);
if(wait){
do{
cr1 = CR1;
cr2 = CR2;
cr3 = CR3;
cr4 = CR4;
cdstat = (cr1>>8)&0x0f;
}while(cdstat==0);
}
}
void cdblock_off(void)
{
smpc_cmd(CDOFF);
SS_CTRL = SAROO_EN | CS0_RAM4M;
}
int cdblock_check(void)
{
int retv, cdstat;
cdc_abort_file();
cdc_cdb_init(0);
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
while(1){
cdc_get_status(&cdstat);
cdstat &= 0x0f;
// cdc_reset_selector会有比较长的BUSY状态。
if(cdstat==STATUS_BUSY)
continue;
if(cdstat==STATUS_OPEN || cdstat==STATUS_NODISC){
return -1;
}
if(cdstat==STATUS_PAUSE)
break;
}
// 0: no Disc
// 1: Audio Disc
// 2: Data Disc
// 3: Pirated Saturn Disc
// 4: Saturn Disc
retv = cdc_auth_device();
return retv;
}
/**********************************************************/
u32 *toc_buf = (u32*)0x06090000;
void show_toc(void)
{
int i;
for(i=0; i<102; i++){
if(toc_buf[i]!=0xffffffff)
printk("TOC %3d: %08x\n", i+1, toc_buf[i]);
}
}
void cdc_file_test(void) void cdc_file_test(void)
{ {
int i; int i;
@ -773,325 +810,12 @@ void cdc_file_test(void)
cdc_get_numsector(1, &free); cdc_get_numsector(1, &free);
printk("cdc_get_numsector 1: %d HIRQ=%04x\n", free, HIRQ); printk("cdc_get_numsector 1: %d HIRQ=%04x\n", free, HIRQ);
cdc_get_buffer_size(&total, &npart, &free); cdc_get_buffer_size(&total, &npart, &free);
}
/**********************************************************/
#define INDIRECT_CALL(addr, return_type, ...) (**(return_type(**)(__VA_ARGS__)) addr)
#define bios_run_cd_player INDIRECT_CALL(0x0600026C, void, void)
//!< mode 0 -> check, 1 -> do auth
#define bios_check_cd_auth INDIRECT_CALL(0x06000270, int, int mode)
#define bios_loadcd_init1 INDIRECT_CALL(0x060002dc, int, int) // 00002650
#define bios_loadcd_init INDIRECT_CALL(0x0600029c, int, int) // 00001904
#define bios_loadcd_read INDIRECT_CALL(0x060002cc, int, void) // 00001912
#define bios_loadcd_boot INDIRECT_CALL(0x06000288, int, void) // 000018A8
void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg);
void _call_04c8(void)
{
void (*go)(void) = (void*)(0x04c8);
go();
*(u32*)(0x25fe00b0) = 0x38803880;
}
void my_cdplayer(void)
{
void (*go)(int);
if(debug_flag&1) sci_init();
printk("\nLoad my multiPlayer ...\n");
go = (void*)0x1d7c;
go(0);
*(u32*)(0x06000348) = 0xffffffff;
memcpy((u8*)0x00280000, _call_04c8, 64);
go = (void*)0x00280000;
go(0);
if(debug_flag&1) sci_init();
*(u32*)(0xffffffb0) = 0;
*(u8 *)(0x2010001f) = 0x1a;
memset((u8*)0x0600a000, 0, 0xf6000);
memset((u8*)0x06000c00, 0, 0x09400);
memset((u8*)0x06000b00, 0, 0x00100);
memcpy((u8*)0x06000000, (u8*)0x20000600, 0x0210);
memcpy((u8*)0x06000220, (u8*)0x20000820, 0x08e0);
memcpy((u8*)0x06001100, (u8*)0x20001100, 0x0700);
memcpy((u8*)0x060002c0, (u8*)0x20001100, 0x0020);
*(u32*)(0x06000358) = (u32)bup_init;
*(u32*)(0x06000234) = 0x02ac;
*(u32*)(0x06000238) = 0x02bc;
*(u32*)(0x0600023c) = 0x0350;
*(u32*)(0x06000328) = 0x04c8;
*(u32*)(0x0600024c) = 0x4843444d;
go = (void*)0x06000680;
go(0);
}
int my_bios_loadcd_init(void)
{
printk("\nmy_bios_loadcd_init!\n");
*(u32*)(0x06000278) = 0;
*(u32*)(0x0600027c) = 0;
cdc_abort_file();
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
cdc_set_size(0);
// This is needed for Yabause: Clear the diskChange flag.
int status;
cdc_get_hwinfo(&status);
cdc_auth_device();
return 0;
}
int my_bios_loadcd_read(void)
{
int status, tm;
u8 *sbuf = (u8*)0x06002000;
char ipstr[64];
printk("\nmy_bios_loadcd_read!\n");
cdc_reset_selector(0, 0);
cdc_cddev_connect(0);
cdc_play_fad(0, 150, 16);
HIRQ = 0;
tm = 10000000;
while(tm){
if(HIRQ&HIRQ_PEND)
break;
tm -= 1;
}
if(tm==0){
printk(" PLAY timeout!\n");
return -1;
}
cdc_get_data(0, 0, 16);
cdc_trans_data(sbuf, 2048*16);
cdc_end_trans(&status);
*(u16*)(0x060003a0) = 1;
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);
return 0;
}
static u16 code_06b8[10] = {
0xd102, // mov.l #0x25fe00b0, r1
0xd203, // mov.l #0x38803880, r2
0x2122, // mov.l r2, @r1
0xd103, // mov.l next_call, r1
0x412b, // jmp @r1
0x4f26, // lds.l @r15+, pr
0x25fe,0x00b0,
0x3880,0x3880,
// 060006cc: .long next_call
};
static void my_06b0(void)
{
if(debug_flag&1) sci_init();
printk("\nbios_set_clock_speed(%d)!\n", *(u32*)(0x06000324));
void (*go)(void) = (void*)0x1800;
go();
*(u32*)(0x25fe00b0) = 0x38803880;
SF = 1;
COMREG = 0x19;
while(SF&1);
}
extern int to_stm32;
extern int gets_from_stm32;
void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg);
void read_1st(void)
{
printk("Read main ...\n");
int retv;
retv = *(u32*)(0x06000284);
void (*go)(void) = (void(*)(void))retv;
go();
patch_game((char*)0x06002020);
*(u32*)(0x06000358) = (u32)bup_init;
*(u32*)(0x0600026c) = (u32)my_cdplayer;
// 0x06000320: 0x060006b0 bios_set_clock_speed
memcpy((u8*)0x060006b8, code_06b8, sizeof(code_06b8));
*(u32*)(0x060006cc) = (u32)my_06b0;
if(game_break_pc){
set_break_pc(game_break_pc, 0);
install_ubr_isr();
// install_isr(ISR_NMI);
// void reloc_vbr(void);
// reloc_vbr();
to_stm32 = 1;
gets_from_stm32 = 1;
*(u32*)(0x22820000) = 0;
}
}
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(void)
{
int retv, ip_size;
my_bios_loadcd_init();
retv = my_bios_loadcd_read();
if(retv)
return retv;
// emulate bios_loadcd_boot
*(u32*)(0x06000290) = 3;
ip_size = bios_loadcd_read();//1912¶ÁÈ¡ipÎļþ
*(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);
}
printk("bios_loadcd_boot retv=%d\n", retv);
return retv;
} }
/**********************************************************/ /**********************************************************/
#define CDROM_syscdinit1(i) \
((**(void(**)(int))0x60002dc)(i))
#define CDROM_syscdinit2() \
((**(void(**)(void))0x600029c)())
void cdc_read_test(void);
void cdc_init1(void)
{
cdc_abort_file();
cdc_cdb_init(0);
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
}
void cdc_init(void)
{
cdc_abort_file();
cdc_cdb_init(0);
cdc_end_trans(NULL);
cdc_reset_selector(0xfc, 0);
cdc_auth_device();
#if 0
CDROM_syscdinit1(3);
CDROM_syscdinit2();
int status;
while(1){
cdc_get_status(&status);
if(status!=0xff)
break;
}
printk("cdc_init done!\n");
cdc_read_test();
#endif
}
int cdc_read_sector(int fad, int size, u8 *buf)
{
int nsec, retv, status, num;
num = (size+3)&0xfffffffc;
cdc_set_size(0);
cdc_reset_selector(0, 0);
cdc_cddev_connect(0);
cdc_play_fad(0, fad, (size+0x7ff)>>11);
while(num>0){
retv = cdc_get_numsector(0, &nsec);
if(retv<0)
return retv;
if(nsec==0)
continue;
if(num>=2048)
nsec=2048;
else
nsec=num;
cdc_get_del_data(0, 0, 1);
cdc_trans_data(buf, nsec);
cdc_end_trans(&status);
buf += nsec;
num -= nsec;
}
return size;
}
void cdc_read_test(void) void cdc_read_test(void)
{ {
int status; int status;

View file

@ -1,4 +1,4 @@
/* /*
* Sega Saturn cartridge flash tool * Sega Saturn cartridge flash tool
* by Anders Montonen, 2012 * by Anders Montonen, 2012
* *
@ -272,6 +272,10 @@ void conio_putc(int ch)
/******************************************************************************/ /******************************************************************************/
int abs(int v)
{
return (v<0)? -v : v;
}
void put_pixel(int x, int y, int c) void put_pixel(int x, int y, int c)
{ {

View file

@ -1,197 +1,249 @@
/*
* Sega Saturn cartridge flash tool
* by Anders Montonen, 2012
*
* Original software by ExCyber
* Graphics routines by Charles MacDonald
*
* Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
*/
#include "vdp2.h" #include "main.h"
#include "smpc.h" #include "smpc.h"
#include "vdp.h"
#include "conio.h" /**********************************************************/
#define bios_loadcd_init INDIRECT_CALL(0x0600029c, int, int) // 调用04c8的代码必须在内部RAM中运行。
static void _call_04c8(void)
#define bios_loadcd_read INDIRECT_CALL(0x060002cc, int, void)
#define bios_loadcd_boot INDIRECT_CALL(0x06000288, int, int)
#if 0
u32 set_sp(u32 addr)
{ {
asm(" void (*go)(void) = (void*)(0x04c8);
mov r15, r0 go();
mov r4, r15 *(u32*)(0x25fe00b0) = 0x38803880;
");
} }
int load_game(void) void my_cdplayer(void)
{ {
int retv, save_sp; void (*go)(int);
cdc_cdb_init(0); if(debug_flag&1) sci_init();
cdc_change_dir(23, 0xffffff); printk("\nLoad my multiPlayer ...\n");
cdc_abort_file();
retv = bios_loadcd_init(0); go = (void*)0x1d7c;
printk("bios_loadcd_init: %d\n", retv); go(0);
save_sp = set_sp(0x06002000); *(u32*)(0x06000348) = 0xffffffff;
while(1){ memcpy((u8*)0x00280000, _call_04c8, 64);
retv = bios_loadcd_boot(0); go = (void*)0x00280000;
printk("bios_loadcd_boot: %d\n", retv); go(0);
if(retv<0)
break;
}
set_sp(save_sp); if(debug_flag&1) sci_init();
return retv; *(u32*)(0xffffffb0) = 0;
} *(u8 *)(0x2010001f) = 0x1a;
#else memset((u8*)0x0600a000, 0, 0xf6000);
memset((u8*)0x06000c00, 0, 0x09400);
memset((u8*)0x06000b00, 0, 0x00100);
memcpy((u8*)0x06000000, (u8*)0x20000600, 0x0210);
memcpy((u8*)0x06000220, (u8*)0x20000820, 0x08e0);
memcpy((u8*)0x06001100, (u8*)0x20001100, 0x0700);
memcpy((u8*)0x060002c0, (u8*)0x20001100, 0x0020);
static inline void set_sr2( unsigned int sr ){ *(u32*)(0x06000358) = (u32)bup_init;
asm volatile ( "ldc\t%0,sr":: "r" (sr) );
}
static inline unsigned int get_sr( void ){ *(u32*)(0x06000234) = 0x02ac;
unsigned int sr; *(u32*)(0x06000238) = 0x02bc;
*(u32*)(0x0600023c) = 0x0350;
*(u32*)(0x06000328) = 0x04c8;
*(u32*)(0x0600024c) = 0x4843444d;
asm volatile ( "stc\tsr,%0": "=r" (sr) ); go = (void*)0x06000680;
return sr; go(0);
}
static inline void set_imask( unsigned int imask ){
unsigned int sr = get_sr();
sr &= ~0x000000f0;
sr |= ( imask << 4 );
set_sr( sr );
}
static inline void set_vbr2( void *vbr ){
asm volatile ( "ldc\t%0,vbr":: "r" (vbr) );
}
static inline void set_gbr2( void *gbr ){
asm volatile ( "ldc\t%0,gbr":: "r" (gbr) );
} }
int load_game(void) int my_bios_loadcd_init(void)
{ {
int retv; printk("\nmy_bios_loadcd_init!\n");
u8 *ip_addr = (u8*)0x06002000;
u32 main_addr;
u32 main_size;
retv = cdc_read_sector(ip_addr, 150, 16);
if(retv<0){
printk("load_game: read ip.bin failed!\n");
return retv;
}
retv = cdc_read_sector((u8*)0x0600a000, 150+20, 1);
if(retv<0){
printk("load_game: read root dir failed!\n");
return retv;
}
memcpy((u8*)0x06000c00, (u8*)0x06002000, 0x0100);
memcpy((u8*)0x060002a0, (u8*)0x060020e0, 0x0020);
*(u32*)(0x060002b0) = 0x06010000;
*(u32*)(0x06000290) = 3;
*(u32*)(0x06002270) = 0x06000284;
*(u32*)(0x06000278) = 0; *(u32*)(0x06000278) = 0;
*(u32*)(0x0600027c) = 0; *(u32*)(0x0600027c) = 0;
main_addr = *(u32*)(0x060020f0); cdc_abort_file();
main_size = *(u32*)(0x0600a052); cdc_end_trans(NULL);
main_offs = *(u32*)(0x0600a04a); cdc_reset_selector(0xfc, 0);
printk("main_offset=%08x main_size=%08x main_addr=%08x\n", main_offs, main_size, main_addr); cdc_set_size(0);
// Setup the vector table area, etc.(all bioses have it at 0x00000600-0x00000810) // This is needed for Yabause: Clear the diskChange flag.
for(i=0; i<0x210; i+=4){ int status;
*(u32*)(0x06000000+i) = *(u32*)(0x00000600+i); cdc_get_hwinfo(&status);
}
// Setup the bios function pointers, etc.(all bioses have it at 0x00000820-0x00001100)
for(i=0; i<0x8e0; i+=4){
*(u32*)(0x06000220+i) = *(u32*)(0x00000820+i);
}
// I'm not sure this is really needed
for(i=0; i<0x700; i+=4){
*(u32*)(0x06001100+i) = *(u32*)(0x00001100+i);
}
// Fix some spots in 0x06000210-0x0600032C area
*(u32*)0x06000234 = 0x000002ac;
*(u32*)0x06000238 = 0x000002bc;
*(u32*)0x0600023c = 0x00000350;
*(u32*)0x06000240 = 0x32524459;
*(u32*)0x0600024c = 0x00000000;
*(u32*)0x06000268 = *(u32*)0x00001344;
*(u32*)0x0600026c = *(u32*)0x00001348;
*(u32*)0x0600029c = *(u32*)0x00001354;
*(u32*)0x060002c4 = *(u32*)0x00001104;
*(u32*)0x060002c8 = *(u32*)0x00001108;
*(u32*)0x060002cc = *(u32*)0x0000110c;
*(u32*)0x060002d0 = *(u32*)0x00001110;
*(u32*)0x060002d4 = *(u32*)0x00001114;
*(u32*)0x060002d8 = *(u32*)0x00001118;
*(u32*)0x060002dc = *(u32*)0x0000111c;
*(u32*)0x06000328 = 0x000004c8;
*(u32*)0x0600032c = 0x00001800;
// Fix SCU interrupts
for(i=0; i<0x80; i+=4){
*(u32*)(0x06000a00+i) = 0x0600083c;
}
set_sr2(0);
set_vbr2(0x06000000);
__asm__ volatile ("mov #0, r0");
__asm__ volatile ("mov #0, r1");
__asm__ volatile ("mov #0, r2");
__asm__ volatile ("mov #0, r3");
__asm__ volatile ("mov #0, r4");
__asm__ volatile ("mov #0, r5");
__asm__ volatile ("mov #0, r6");
__asm__ volatile ("mov #0, r7");
__asm__ volatile ("mov #0, r8");
__asm__ volatile ("mov #0, r9");
__asm__ volatile ("mov #0, r10");
__asm__ volatile ("mov #0, r11");
__asm__ volatile ("mov #0, r12");
__asm__ volatile ("mov #0, r13");
__asm__ volatile ("mov #0, r14");
__asm__ volatile ("lds r14, pr");
__asm__ volatile ("ldc r14, gbr");
__asm__ volatile ("lds r14, mach");
__asm__ volatile ("lds r14, macl");
setStackptr(0x6002000, 0x6002e00);
return 0; return 0;
} }
int my_bios_loadcd_read(void)
{
int status, tm;
u8 *sbuf = (u8*)0x06002000;
char ipstr[64];
printk("\nmy_bios_loadcd_read!\n");
cdc_reset_selector(0, 0);
cdc_cddev_connect(0);
cdc_play_fad(0, 150, 16);
HIRQ = 0;
tm = 10000000;
while(tm){
if(HIRQ&HIRQ_PEND)
break;
tm -= 1;
}
if(tm==0){
printk(" PLAY timeout!\n");
return -1;
}
cdc_get_data(0, 0, 16);
cdc_trans_data(sbuf, 2048*16);
cdc_end_trans(&status);
*(u16*)(0x060003a0) = 1;
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);
return 0;
}
static u16 code_06b8[10] = {
0xd102, // mov.l #0x25fe00b0, r1
0xd203, // mov.l #0x38803880, r2
0x2122, // mov.l r2, @r1
0xd103, // mov.l next_call, r1
0x412b, // jmp @r1
0x4f26, // lds.l @r15+, pr
0x25fe,0x00b0,
0x3880,0x3880,
// 060006cc: .long next_call
};
static void my_06b0(void)
{
if(debug_flag&1) sci_init();
printk("\nbios_set_clock_speed(%d)!\n", *(u32*)(0x06000324));
void (*go)(void) = (void*)0x1800;
go();
*(u32*)(0x25fe00b0) = 0x38803880;
SF = 1;
COMREG = 0x19;
while(SF&1);
}
static void read_1st(void)
{
printk("Read main ...\n");
int retv;
retv = *(u32*)(0x06000284);
void (*go)(void) = (void(*)(void))retv;
go();
patch_game((char*)0x06002020);
*(u32*)(0x06000358) = (u32)bup_init;
*(u32*)(0x0600026c) = (u32)my_cdplayer;
// 0x06000320: 0x060006b0 bios_set_clock_speed
memcpy((u8*)0x060006b8, code_06b8, sizeof(code_06b8));
*(u32*)(0x060006cc) = (u32)my_06b0;
if(game_break_pc){
set_break_pc(game_break_pc, 0);
install_ubr_isr();
// install_isr(ISR_NMI);
// void reloc_vbr(void);
// reloc_vbr();
to_stm32 = 1;
gets_from_stm32 = 1;
*(u32*)(0x22820000) = 0;
}
}
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();
#if 1
my_bios_loadcd_boot(0, 0x1904);
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
retv = my_bios_loadcd_read();
if(retv)
return retv;
// emulate bios_loadcd_boot
*(u32*)(0x06000290) = 3;
ip_size = bios_loadcd_read();//1912读取ip文件
#endif #endif
if(type>0){
// 光盘游戏。需要通知MCU加载SAVE。
memcpy((void*)(TMPBUFF_ADDR+0x10), (u8*)0x06002020, 16);
*(u8*)(TMPBUFF_ADDR+0x20) = 0;
SS_ARG = 0;
SS_CMD = SSCMD_LSAVE;
while(SS_CMD);
}
*(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);
}
printk("bios_loadcd_boot retv=%d\n", retv);
return retv;
}
/**********************************************************/

View file

@ -545,8 +545,10 @@ u32 bup_set_date(BUPDATE *bdt)
/******************************************************************************/ /******************************************************************************/
void bup_init(u8 *lib_addr, u8 *work_addr, BUPCFG *cfg) void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg_ptr)
{ {
BUPCFG *cfg = (BUPCFG*)cfg_ptr;
if(debug_flag&1) if(debug_flag&1)
sci_init(); sci_init();

View file

@ -6,7 +6,7 @@
int lang_id = 0; int lang_id = 0;
#define LANG_STR_NR 16 #define LANG_STR_NR 19
#define LANG_NR 8 #define LANG_NR 8
typedef struct _str_entry typedef struct _str_entry
@ -41,6 +41,9 @@ char *lang_zhcn[LANG_STR_NR] = {
"升级失败!", "升级失败!",
"升级完成,请重新开机!", "升级完成,请重新开机!",
"SAROO Boot Menu", "SAROO Boot Menu",
"检查光盘中......",
"未发现光盘!",
"不是游戏光盘!",
}; };
@ -61,6 +64,9 @@ char *lang_en[LANG_STR_NR] = {
"Update Failed!", "Update Failed!",
"Update Finish! Please PowerOn again!", "Update Finish! Please PowerOn again!",
"SAROO Boot Menu", "SAROO Boot Menu",
"Checking Disc ......",
"No Disc Found!",
"Not a Game Disc!",
}; };
@ -81,6 +87,9 @@ char *lang_ptbr[LANG_STR_NR] = {
"Erro ao atualizar!", "Erro ao atualizar!",
"Finalizado, reinicie o sistema!", "Finalizado, reinicie o sistema!",
"SAROO Menu de Inicialização", "SAROO Menu de Inicialização",
"Verificando o disco ......",
"Sem CD!",
"Não é um disco de jogo!",
}; };
@ -101,6 +110,9 @@ char *lang_ja[LANG_STR_NR] = {
"アップデート失敗!", "アップデート失敗!",
"アップデート完了、再起動してください!", "アップデート完了、再起動してください!",
"SAROO ブートメニュー", "SAROO ブートメニュー",
"ディスクを確認してください...",
"ディスクなし!",
"ゲームディスクじゃないよ!",
}; };

View file

@ -463,7 +463,7 @@ static int sel_handle(int ctrl)
SS_CMD = SSCMD_LOADDISC; SS_CMD = SSCMD_LOADDISC;
while(SS_CMD); while(SS_CMD);
retv = bios_cd_cmd(); retv = bios_cd_cmd(0);
if(retv){ if(retv){
char buf[40]; char buf[40];
sprintf(buf, TT("游戏启动失败! %d"), retv); sprintf(buf, TT("游戏启动失败! %d"), retv);
@ -556,18 +556,23 @@ int main_handle(int ctrl)
select_game(); select_game();
return MENU_RESTART; return MENU_RESTART;
}else if(index==1){ }else if(index==1){
// SAROOO Off, CDBlock On cdblock_on(0);
SS_CTRL = CS0_RAM4M;
smpc_cmd(CDON);
bios_run_cd_player(); bios_run_cd_player();
return MENU_RESTART; return MENU_RESTART;
}else if(index==2){ }else if(index==2){
// SAROOO Off, CDBlock On menu_status(&main_menu, TT("检查光盘中......"));
SS_CTRL = CS0_RAM4M; cdblock_on(1);
smpc_cmd(CDON); int retv = cdblock_check();
if(retv<0){
menu_status(&main_menu, TT("未发现光盘!"));
return 0;
}else if(retv!=4){
menu_status(&main_menu, TT("不是游戏光盘!"));
return 0;
}
menu_status(&main_menu, TT("游戏启动中......")); menu_status(&main_menu, TT("游戏启动中......"));
int retv = bios_cd_cmd(); retv = bios_cd_cmd(4);
if(retv){ if(retv){
char buf[40]; char buf[40];
sprintf(buf, TT("游戏启动失败! %d"), retv); sprintf(buf, TT("游戏启动失败! %d"), retv);
@ -670,11 +675,7 @@ int _main(void)
printk_putc = NULL; printk_putc = NULL;
} }
cdblock_off();
// CDBlock Off, SAROOO On
smpc_cmd(CDOFF);
SS_CTRL = (SAROO_EN | CS0_RAM4M);
if((debug_flag&0x0003)==0x0003){ if((debug_flag&0x0003)==0x0003){
sci_shell(); sci_shell();

View file

@ -44,6 +44,7 @@ typedef unsigned long long u64;
#define SSCMD_FILEWR 0x0007 #define SSCMD_FILEWR 0x0007
#define SSCMD_LISTBINS 0x0008 #define SSCMD_LISTBINS 0x0008
#define SSCMD_SSAVE 0x0009 #define SSCMD_SSAVE 0x0009
#define SSCMD_LSAVE 0x000a
#define IMGINFO_ADDR 0x22080000 #define IMGINFO_ADDR 0x22080000
@ -52,15 +53,139 @@ typedef unsigned long long u64;
/*****************************************************************************/ /*****************************************************************************/
// cdblock
typedef struct {
u16 cr1;
u16 cr2;
u16 cr3;
u16 cr4;
}CDCMD;
typedef struct {
int fad;
int size;
u8 unit;
u8 gap;
u8 fn;
u8 attr;
}CdcFile;
#define CR1 REG16(0x25890018)
#define CR2 REG16(0x2589001c)
#define CR3 REG16(0x25890020)
#define CR4 REG16(0x25890024)
#define HIRQ REG16(0x25890008)
#define HMSK REG16(0x2589000c)
#define HIRQ_CMOK 0x0001
#define HIRQ_DRDY 0x0002
#define HIRQ_CSCT 0x0004
#define HIRQ_BFUL 0x0008
#define HIRQ_PEND 0x0010
#define HIRQ_DCHG 0x0020
#define HIRQ_ESEL 0x0040
#define HIRQ_EHST 0x0080
#define HIRQ_ECPY 0x0100
#define HIRQ_EFLS 0x0200
#define HIRQ_SCDQ 0x0400
#define STATUS_BUSY 0x00
#define STATUS_PAUSE 0x01
#define STATUS_STANDBY 0x02
#define STATUS_PLAY 0x03
#define STATUS_SEEK 0x04
#define STATUS_SCAN 0x05
#define STATUS_OPEN 0x06
#define STATUS_NODISC 0x07
#define STATUS_RETRY 0x08
#define STATUS_ERROR 0x09
#define STATUS_FATAL 0x0a
#define STATUS_PERIODIC 0x20
#define STATUS_TRANSFER 0x40
#define STATUS_WAIT 0x80
#define STATUS_REJECT 0xff
#define INDIRECT_CALL(addr, return_type, ...) (**(return_type(**)(__VA_ARGS__)) addr) #define INDIRECT_CALL(addr, return_type, ...) (**(return_type(**)(__VA_ARGS__)) addr)
#define bios_run_cd_player INDIRECT_CALL(0x0600026C, void, void)
int bios_cd_cmd(void); #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_read INDIRECT_CALL(0x060002cc, int, void) // 00001912
#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)
void clear_hirq(int mask);
int wait_hirq(int mask);
int wait_status(int wait);
int cdc_cmd(int wait, CDCMD *cmd, CDCMD *resp, char *cmdname);
int cdc_get_status(int *status);
int cdc_get_hwinfo(int *status);
int cdc_cdb_init(int standby);
int cdc_end_trans(int *cdwnum);
int cdc_get_toc(u8 *buf);
int cdc_play_fad(int mode, int start_fad, int range);
int cdc_cddev_connect(int filter);
int cdc_get_cddev(int *selnum);
int cdc_set_filter_range(int selnum, int start_fad, int num_sector);
int cdc_get_filter_range(int selnum, int *fad, int *num_sector);
int cdc_set_filter_mode(int selnum, int mode);
int cdc_get_filter_mode(int selnum, int *mode);
int cdc_set_filter_connect(int selnum, int c_true, int c_false);
int cdc_get_filter_connect(int selnum, int *c_true, int *c_false);
int cdc_reset_selector(int flag, int selnum);
int cdc_get_buffer_size(int *total, int *pnum, int *free);
int cdc_get_numsector(int selnum, int *snum);
int cdc_calc_actsize(int bufno, int spos, int snum);
int cdc_get_actsize(int *actsize);
int cdc_get_sector_info(int bufno, int secno, int *fad);
int cdc_set_size(int size);
int cdc_get_data(int bufnum, int spos, int snum);
int cdc_get_del_data(int bufnum, int spos, int snum);
void cdc_trans_data(u8 *buf, int length);
int cdc_auth_status(int *status);
int cdc_auth_device(void);
int cdc_change_dir(int selnum, int fid);
int cdc_read_dir(int selnum, int fid);
int cdc_get_file_scope(int *fid, int *fnum, int *drend);
int cdc_get_file_info(int fid, CdcFile *buf);
int cdc_read_file(int selnum, int fid, int offset);
int cdc_abort_file(void);
void cdc_dump(int count);
void show_selector(int id);
void cdblock_on(int wait);
void cdblock_off(void);
int cdblock_check(void);
int bios_cd_cmd(int type);
int cdc_read_sector(int fad, int size, u8 *buf); int cdc_read_sector(int fad, int size, u8 *buf);
void my_cdplayer(void); void my_cdplayer(void);
void bup_init(u8 *lib_addr, u8 *work_addr, void *cfg);
/*****************************************************************************/ /*****************************************************************************/
@ -125,6 +250,8 @@ int sci_getc(int timeout);
/*****************************************************************************/ /*****************************************************************************/
extern int to_stm32; extern int to_stm32;
extern int gets_from_stm32;
extern void (*printk_putc)(int ch); extern void (*printk_putc)(int ch);
int printk(char *fmt, ...); int printk(char *fmt, ...);
@ -144,6 +271,7 @@ void *memset(void *s, int v, int n);
void *memcpy(void *to, void *from, int n); void *memcpy(void *to, void *from, int n);
int memcmp(void *dst, void *src, int n); int memcmp(void *dst, void *src, int n);
int tiny_xmodem_recv(u8 *dest);
/*****************************************************************************/ /*****************************************************************************/

View file

@ -272,10 +272,24 @@ void sci_shell(void)
CMD(d) { dump(argc, arg, 0); } CMD(d) { dump(argc, arg, 0); }
CMD(go){ void (*go)(void) = (void(*)(void))arg[0]; go(); } CMD(go){ void (*go)(void) = (void(*)(void))arg[0]; go(); }
CMD(t) { cd_cmd(); } CMD(t) {
CMD(f) { cdc_file_test(); } void cd_cmd(void);
cd_cmd();
}
CMD(f) {
void cdc_file_test(void);
cdc_file_test();
}
CMD(m) { bios_run_cd_player(); } /* 运行系统CD播放器 */ CMD(m) { bios_run_cd_player(); } /* 运行系统CD播放器 */
CMD(n) { bios_cd_cmd(); } /* 启动游戏 */ CMD(n) { bios_cd_cmd(0); } /* 启动游戏 */
CMD(cds) {
void cdc_dump(int count);
int count = 1;
if(argc>0)
count = arg[0];
cdc_dump(count);
}
CMD(menu) { menu_init(); } CMD(menu) { menu_init(); }
CMD(nmi) { CMD(nmi) {
@ -345,20 +359,13 @@ void sci_shell(void)
CMD(c) { CMD(c) {
/* 打开系统光驱 */ /* 打开系统光驱 */
smpc_cmd(CDOFF); cdblock_on(1);
printk("CDOFF ...\n"); int retv = cdblock_check();
printk("CDOFF ...\n"); printk("cdblock_check: %d\n", retv);
smpc_cmd(CDON);
printk("CDON ...\n");
printk("CDON ...\n");
REG16(0x25897004) = 0x0000;
} }
CMD(s) { CMD(s) {
/* 关闭系统光驱, 打开sarooo */ /* 关闭系统光驱, 打开sarooo */
smpc_cmd(CDOFF); cdblock_off();
printk("CDOFF ...\n");
printk("CDOFF ...\n");
REG16(0x25897004) = 0x8000;
} }
CMD(listb){ CMD(listb){
@ -378,7 +385,7 @@ void sci_shell(void)
/* 下载到ram并运行. 如果指定了地址, 则只下载. */ /* 下载到ram并运行. 如果指定了地址, 则只下载. */
int xm_len, xm_addr; int xm_len, xm_addr;
xm_addr = (argc>0)? arg[0] : 0x06004000; xm_addr = (argc>0)? arg[0] : 0x06004000;
xm_len = tiny_xmodem_recv(xm_addr); xm_len = tiny_xmodem_recv((u8*)xm_addr);
printk(" \n"); printk(" \n");
printk(" \n"); printk(" \n");
printk("Download to %08x, size %08x\n", xm_addr, xm_len); printk("Download to %08x, size %08x\n", xm_addr, xm_len);

View file

@ -17,7 +17,7 @@
#define DLY_1S 1000 #define DLY_1S 1000
int tiny_xmodem_recv(unsigned char *dest) int tiny_xmodem_recv(u8 *dest)
{ {
int pk_size, pk_num, pk_chk, check_sum, pk_sum, next_pk; int pk_size, pk_num, pk_chk, check_sum, pk_sum, next_pk;
int i, c, len; int i, c, len;

View file

@ -16,27 +16,27 @@ void (*game_break_handle)(REGS *reg);
/**********************************************************/ /**********************************************************/
static inline u32 get_vbr(void) inline u32 get_vbr(void)
{ {
u32 vbr; u32 vbr;
__asm volatile ( "stc\tvbr,%0": "=r" (vbr) ); __asm volatile ( "stc\tvbr,%0": "=r" (vbr) );
return vbr; return vbr;
} }
static inline void set_vbr(u32 vbr) inline void set_vbr(u32 vbr)
{ {
__asm volatile ( "ldc\t%0,vbr":: "r" (vbr) ); __asm volatile ( "ldc\t%0,vbr":: "r" (vbr) );
} }
static inline u32 get_sr(void) inline u32 get_sr(void)
{ {
u32 sr; u32 sr;
__asm volatile ( "stc\tsr,%0": "=r" (sr) ); __asm volatile ( "stc\tsr,%0": "=r" (sr) );
return sr; return sr;
} }
static inline void set_sr(u32 sr) inline void set_sr(u32 sr)
{ {
__asm volatile ( "ldc\t%0,sr":: "r" (sr) ); __asm volatile ( "ldc\t%0,sr":: "r" (sr) );
} }
@ -118,7 +118,7 @@ void reloc_vbr(void)
{ {
u32 old_vbr = get_vbr(); u32 old_vbr = get_vbr();
memcpy((void*)new_vtable, (void*)old_vbr, 1024); memcpy((void*)new_vtable, (void*)old_vbr, 1024);
set_vbr(new_vtable); set_vbr((u32)new_vtable);
printk("New VBR at %08x\n", new_vtable); printk("New VBR at %08x\n", new_vtable);
} }

View file

@ -433,6 +433,77 @@ play_cd: start=0080874a end=00800001 mode=00
========================================================================= =========================================================================
Saturn的时钟配置:
+------+---------+------+-----------+-----------+
| | XTAL | DIV | 1708(320) | 1820(352) |
+------+---------+------+-----------+-----------+
| PAL | 14.318 | 910 | 26.873875 | 28.636000 |
+------+---------+------+-----------+-----------+
| NTSC | 17.7344 | 1135 | 26.687538 | 28.437540 |
+------+---------+------+-----------+-----------+
=========================================================================
Saturn存档格式(BackUPram)
BUP位于0x00180000处大小64K。因为此处地址空间是16位的但所用的SRAM芯片是8位的所以偶
地址数据悬空(读出为FF)奇地址才是有效数据。所以BUP实际大小32K。
BUP中的数据以64字节为一块来组织。一共有512个块。前两个块系统保留。块0是标志
"BackUpRam Format"重复4次。块1全0。
其余的块头部4个字节是标志。0x80000000表示一个save的开始。0x00000000表示普通块。块的空闲
与否需要解析每个save来判断。
save开始块结构:
00: 80000000
04: 存档名11字节。
0f: 语言标志。
10: 存档注释10个字节。
1a: 存档日期编码4字节。
1e: 存档字节大小4字节。
22: 存档所占块列表。以0000结束。开始块用完则延续到下一个块。需要跳过块的前4个字节。
注意如果20指示的存档大小可以放在开始块之内则不需要占用块列表了。
块列表后面就是实际存档数据了。块列表不包括开始块。
=========================================================================
自定义存档格式(SaroSave)
前64字节是文件头接着64字节是块占用位图。
32K的存档块大小是64字节共512个块可用64字节的位图表示。
存档大小加倍,则块大小也加倍,这样位图大小不变。
存档开始块占用一个块。存档数据占用的块也用64字节位图描述。数据位图不包括开始块与位图块。
若是32K存档位图占用开始块后面的块。若是大于32K的存档位图位于开始块内部。
文件头
00: "SaroSave"
08: 存档字节大小
0c: 块大小
0e: 空闲块数量
20: 游戏ID
3e第一个save的块编号
save开始块结构:
00: 存档名11字节。
0c: 存档字节大小4字节。
10: 存档注释10个字节。
1a: 00
1b: 语言标志。
1c: 存档日期编码4字节。
3e: 下一个save的块编号。
=========================================================================

View file

@ -1,5 +1,13 @@
# SAROO config file # SAROO config file
# 可用配置: # 可用配置:
# lang_id=x
# 选择菜单语言: 0:中文 1:EN 2:PTBR 3:JA
# debug=xxxxxxxx
# 各种调试选项
# auto_update:
# MCU自动升级固件
# play_delay=xxxx
# PLAY开始前的延时。十进制us单位。
# sector_delay=xxxx # sector_delay=xxxx
# 每读一个扇区后的延时。十进制us单位。 # 每读一个扇区后的延时。十进制us单位。
# exmem_1M # exmem_1M
@ -15,7 +23,7 @@
# #
[global] [global]
lang_id = 0
# Final Fight Revenge # Final Fight Revenge