mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
initial import
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
2cadbd5e56
commit
cc68a136aa
341 changed files with 180839 additions and 0 deletions
189
Pico/Area.c
Normal file
189
Pico/Area.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
// ym2612
|
||||
#include "sound/ym2612.h"
|
||||
|
||||
// sn76496
|
||||
extern int *sn76496_regs;
|
||||
|
||||
|
||||
struct PicoArea { void *data; int len; char *name; };
|
||||
|
||||
// strange observation on Symbian OS 9.1, m600 organizer fw r3a06:
|
||||
// taking an address of fread or fwrite causes "application could't be started" error
|
||||
// on startup randomly depending on binary layout of executable file.
|
||||
|
||||
arearw *areaRead = (arearw *) 0; // fread; // read and write function pointers for
|
||||
arearw *areaWrite = (arearw *) 0; // fwrite; // gzip save state ability
|
||||
|
||||
|
||||
// Scan one variable and callback
|
||||
static int ScanVar(void *data,int len,char *name,void *PmovFile,int PmovAction)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((PmovAction&3)==1) ret = areaWrite(data,1,len,PmovFile);
|
||||
if ((PmovAction&3)==2) ret = areaRead (data,1,len,PmovFile);
|
||||
return (ret != len);
|
||||
}
|
||||
|
||||
#define SCAN_VAR(x,y) ScanVar(&x,sizeof(x),y,PmovFile,PmovAction);
|
||||
#define SCANP(x) ScanVar(&Pico.x,sizeof(Pico.x),#x,PmovFile,PmovAction);
|
||||
|
||||
// Pack the cpu into a common format:
|
||||
static int PackCpu(unsigned char *cpu)
|
||||
{
|
||||
unsigned int pc=0;
|
||||
|
||||
#ifdef EMU_A68K
|
||||
memcpy(cpu,M68000_regs.d,0x40);
|
||||
pc=M68000_regs.pc;
|
||||
*(unsigned char *)(cpu+0x44)=(unsigned char)M68000_regs.ccr;
|
||||
*(unsigned char *)(cpu+0x45)=(unsigned char)M68000_regs.srh;
|
||||
*(unsigned int *)(cpu+0x48)=M68000_regs.isp;
|
||||
#endif
|
||||
|
||||
#ifdef EMU_C68K
|
||||
memcpy(cpu,PicoCpu.d,0x40);
|
||||
pc=PicoCpu.pc-PicoCpu.membase;
|
||||
*(unsigned int *)(cpu+0x44)=CycloneGetSr(&PicoCpu);
|
||||
*(unsigned int *)(cpu+0x48)=PicoCpu.osp;
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
memcpy(cpu,m68ki_cpu.dar,0x40);
|
||||
pc=m68ki_cpu.pc;
|
||||
*(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
|
||||
*(unsigned int *)(cpu+0x48)=m68ki_cpu.sp[0];
|
||||
#endif
|
||||
|
||||
*(unsigned int *)(cpu+0x40)=pc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int UnpackCpu(unsigned char *cpu)
|
||||
{
|
||||
unsigned int pc=0;
|
||||
|
||||
pc=*(unsigned int *)(cpu+0x40);
|
||||
|
||||
#ifdef EMU_A68K
|
||||
memcpy(M68000_regs.d,cpu,0x40);
|
||||
M68000_regs.pc=pc;
|
||||
M68000_regs.ccr=*(unsigned char *)(cpu+0x44);
|
||||
M68000_regs.srh=*(unsigned char *)(cpu+0x45);
|
||||
M68000_regs.isp=*(unsigned int *)(cpu+0x48);
|
||||
#endif
|
||||
|
||||
#ifdef EMU_C68K
|
||||
CycloneSetSr(&PicoCpu, *(unsigned int *)(cpu+0x44));
|
||||
PicoCpu.osp=*(unsigned int *)(cpu+0x48);
|
||||
memcpy(PicoCpu.d,cpu,0x40);
|
||||
PicoCpu.membase=0;
|
||||
PicoCpu.pc =PicoCpu.checkpc(pc); // Base pc
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
memcpy(m68ki_cpu.dar,cpu,0x40);
|
||||
m68ki_cpu.pc=pc;
|
||||
m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
|
||||
m68ki_cpu.sp[0]=*(unsigned int *)(cpu+0x48);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Scan the contents of the virtual machine's memory for saving or loading
|
||||
static int PicoAreaScan(int PmovAction,unsigned int ver, void *PmovFile)
|
||||
{
|
||||
void *ym2612_regs;
|
||||
unsigned char cpu[0x60];
|
||||
unsigned char cpu_z80[0x60];
|
||||
int ret;
|
||||
|
||||
memset(&cpu,0,sizeof(cpu));
|
||||
memset(&cpu_z80,0,sizeof(cpu_z80));
|
||||
|
||||
ym2612_regs = YM2612GetRegs();
|
||||
|
||||
if (PmovAction&4)
|
||||
{
|
||||
Pico.m.scanline=0;
|
||||
|
||||
// Scan all the memory areas:
|
||||
SCANP(ram) SCANP(vram) SCANP(zram) SCANP(cram) SCANP(vsram)
|
||||
|
||||
// Pack, scan and unpack the cpu data:
|
||||
if((PmovAction&3)==1) PackCpu(cpu);
|
||||
//SekInit(); // notaz: do we really have to do this here?
|
||||
//PicoMemInit();
|
||||
SCAN_VAR(cpu,"cpu")
|
||||
if((PmovAction&3)==2) UnpackCpu(cpu);
|
||||
|
||||
SCAN_VAR(Pico.m ,"misc")
|
||||
SCAN_VAR(Pico.video,"video")
|
||||
|
||||
|
||||
if(ver == 0x0030) { // zram was being saved incorrectly in 0x0030 (byteswaped?)
|
||||
Byteswap(Pico.zram, 0x2000);
|
||||
return 0; // do not try to load sound stuff
|
||||
}
|
||||
|
||||
//SCAN_VAR(Pico.s ,"sound")
|
||||
// notaz: save/load z80, YM2612, sn76496 states instead of Pico.s (which is unused anyway)
|
||||
if(PicoOpt&7) {
|
||||
if((PmovAction&3)==1) z80_pack(cpu_z80);
|
||||
ret = SCAN_VAR(cpu_z80,"cpu_z80")
|
||||
// do not unpack if we fail to load z80 state
|
||||
if((PmovAction&3)==2) {
|
||||
if(ret) z80_reset();
|
||||
else z80_unpack(cpu_z80);
|
||||
}
|
||||
}
|
||||
if(PicoOpt&3)
|
||||
ScanVar(sn76496_regs,28*4,"SN76496state", PmovFile, PmovAction); // regs and other stuff
|
||||
if(PicoOpt&1) {
|
||||
ScanVar(ym2612_regs, 0x200+4, "YM2612state", PmovFile, PmovAction); // regs + addr line
|
||||
if((PmovAction&3)==2) YM2612PicoStateLoad(); // reload YM2612 state from it's regs
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper code to save/load to a file handle
|
||||
|
||||
// Save or load the state from PmovFile:
|
||||
int PmovState(int PmovAction, void *PmovFile)
|
||||
{
|
||||
int minimum=0;
|
||||
unsigned char head[32];
|
||||
|
||||
memset(head,0,sizeof(head));
|
||||
|
||||
// Find out minimal compatible version:
|
||||
//PicoAreaScan(PmovAction&0xc,&minimum);
|
||||
minimum = 0x0021;
|
||||
|
||||
memcpy(head,"Pico",4);
|
||||
*(unsigned int *)(head+0x8)=PicoVer;
|
||||
*(unsigned int *)(head+0xc)=minimum;
|
||||
|
||||
// Scan header:
|
||||
if (PmovAction&1) areaWrite(head,1,sizeof(head),PmovFile);
|
||||
if (PmovAction&2) areaRead (head,1,sizeof(head),PmovFile);
|
||||
|
||||
// Scan memory areas:
|
||||
PicoAreaScan(PmovAction, *(unsigned int *)(head+0x8), PmovFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
197
Pico/Cart.c
Normal file
197
Pico/Cart.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
void Byteswap(unsigned char *data,int len)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
if (len<2) return; // Too short
|
||||
|
||||
do
|
||||
{
|
||||
unsigned short *pd=(unsigned short *)(data+i);
|
||||
int value=*pd; // Get 2 bytes
|
||||
|
||||
value=(value<<8)|(value>>8); // Byteswap it
|
||||
*pd=(unsigned short)value; // Put 2b ytes
|
||||
i+=2;
|
||||
}
|
||||
while (i+2<=len);
|
||||
}
|
||||
|
||||
// Interleve a 16k block and byteswap
|
||||
static int InterleveBlock(unsigned char *dest,unsigned char *src)
|
||||
{
|
||||
int i=0;
|
||||
for (i=0;i<0x2000;i++) dest[(i<<1) ]=src[ i]; // Odd
|
||||
for (i=0;i<0x2000;i++) dest[(i<<1)+1]=src[0x2000+i]; // Even
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decode a SMD file
|
||||
static int DecodeSmd(unsigned char *data,int len)
|
||||
{
|
||||
unsigned char *temp=NULL;
|
||||
int i=0;
|
||||
|
||||
temp=(unsigned char *)malloc(0x4000);
|
||||
if (temp==NULL) return 1;
|
||||
memset(temp,0,0x4000);
|
||||
|
||||
// Interleve each 16k block and shift down by 0x200:
|
||||
for (i=0; i+0x4200<=len; i+=0x4000)
|
||||
{
|
||||
InterleveBlock(temp,data+0x200+i); // Interleve 16k to temporary buffer
|
||||
memcpy(data+i,temp,0x4000); // Copy back in
|
||||
}
|
||||
|
||||
free(temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *PicoCartAlloc(int filesize)
|
||||
{
|
||||
int alloc_size;
|
||||
unsigned char *rom;
|
||||
|
||||
if (PicoMCD & 1) {
|
||||
dprintf("sizeof(mcd_state): %i", sizeof(mcd_state));
|
||||
if (filesize > 0x20000) return NULL; // invalid BIOS
|
||||
rom=(unsigned char *)malloc(sizeof(mcd_state));
|
||||
if (rom) memset(rom, 0, sizeof(mcd_state));
|
||||
return rom;
|
||||
}
|
||||
|
||||
alloc_size=filesize+0x7ffff;
|
||||
if((filesize&0x3fff)==0x200) alloc_size-=0x200;
|
||||
alloc_size&=~0x7ffff; // use alloc size of multiples of 512K, so that memhandlers could be set up more efficiently
|
||||
if((filesize&0x3fff)==0x200) alloc_size+=0x200;
|
||||
else if(alloc_size-filesize < 4) alloc_size+=4; // padding for out-of-bound exec protection
|
||||
//dprintf("alloc_size: %x\n", alloc_size);
|
||||
|
||||
// Allocate space for the rom plus padding
|
||||
rom=(unsigned char *)malloc(alloc_size);
|
||||
if(rom) memset(rom+alloc_size-0x80000,0,0x80000);
|
||||
return rom;
|
||||
}
|
||||
|
||||
int PicoCartLoad(FILE *f,unsigned char **prom,unsigned int *psize)
|
||||
{
|
||||
unsigned char *rom=NULL; int size;
|
||||
if (f==NULL) return 1;
|
||||
|
||||
fseek(f,0,SEEK_END); size=ftell(f); fseek(f,0,SEEK_SET);
|
||||
if (size <= 0) return 1;
|
||||
if (PicoMCD & 1) {
|
||||
if (size > 0x20000) return 1; // invalid BIOS
|
||||
size = 0xe0000;
|
||||
} else {
|
||||
size=(size+3)&~3; // Round up to a multiple of 4
|
||||
}
|
||||
|
||||
// Allocate space for the rom plus padding
|
||||
rom=PicoCartAlloc(size);
|
||||
if (rom==NULL) return 1; // { fclose(f); return 1; }
|
||||
|
||||
fread(rom,1,size,f); // Load up the rom
|
||||
// fclose(f); // this is confusing. From now on, caller should close it, because it opened this.
|
||||
|
||||
// Check for SMD:
|
||||
if ((size&0x3fff)==0x200) { DecodeSmd(rom,size); size-=0x200; } // Decode and byteswap SMD
|
||||
else Byteswap(rom,size); // Just byteswap
|
||||
|
||||
if (prom) *prom=rom;
|
||||
if (psize) *psize=size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Insert/remove a cartridge:
|
||||
int PicoCartInsert(unsigned char *rom,unsigned int romsize)
|
||||
{
|
||||
// notaz: add a 68k "jump one op back" opcode to the end of ROM.
|
||||
// This will hang the emu, but will prevent nasty crashes.
|
||||
// note: 4 bytes are padded to every ROM
|
||||
if(rom != NULL)
|
||||
*(unsigned long *)(rom+romsize) = 0xFFFE4EFA; // 4EFA FFFE byteswapped
|
||||
|
||||
SRam.resize=1;
|
||||
Pico.rom=rom;
|
||||
Pico.romsize=romsize;
|
||||
|
||||
return PicoReset(1);
|
||||
}
|
||||
|
||||
int PicoUnloadCart(unsigned char* romdata)
|
||||
{
|
||||
free(romdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _UNZIP_SUPPORT
|
||||
|
||||
// notaz
|
||||
#include "../unzip/unzip.h"
|
||||
|
||||
// nearly same as PicoCartLoad, but works with zipfiles
|
||||
int CartLoadZip(const char *fname, unsigned char **prom, unsigned int *psize)
|
||||
{
|
||||
unsigned char *rom=0;
|
||||
struct zipent* zipentry;
|
||||
int size;
|
||||
ZIP *zipfile = openzip(fname);
|
||||
|
||||
if(!zipfile) return 1;
|
||||
|
||||
// find first bin or smd
|
||||
while((zipentry = readzip(zipfile)) != 0)
|
||||
{
|
||||
char *ext;
|
||||
if(strlen(zipentry->name) < 5) continue;
|
||||
ext = zipentry->name+strlen(zipentry->name)-4;
|
||||
|
||||
if(!strcasecmp(ext, ".bin") || !strcasecmp(ext, ".smd") || !strcasecmp(ext, ".gen")) break;
|
||||
}
|
||||
|
||||
if(!zipentry) {
|
||||
closezip(zipfile);
|
||||
return 4; // no roms
|
||||
}
|
||||
|
||||
size = zipentry->uncompressed_size;
|
||||
|
||||
size=(size+3)&~3; // Round up to a multiple of 4
|
||||
|
||||
// Allocate space for the rom plus padding
|
||||
rom=PicoCartAlloc(size);
|
||||
if (rom==NULL) { closezip(zipfile); return 2; }
|
||||
|
||||
if(readuncompresszip(zipfile, zipentry, (char *)rom) != 0) {
|
||||
free(rom);
|
||||
rom = 0;
|
||||
closezip(zipfile);
|
||||
return 5; // unzip failed
|
||||
}
|
||||
|
||||
closezip(zipfile);
|
||||
|
||||
// Check for SMD:
|
||||
if ((size&0x3fff)==0x200) { DecodeSmd(rom,size); size-=0x200; } // Decode and byteswap SMD
|
||||
else Byteswap(rom,size); // Just byteswap
|
||||
|
||||
if (prom) *prom=rom;
|
||||
if (psize) *psize=size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
1291
Pico/Draw.c
Normal file
1291
Pico/Draw.c
Normal file
File diff suppressed because it is too large
Load diff
1429
Pico/Draw.s
Normal file
1429
Pico/Draw.s
Normal file
File diff suppressed because it is too large
Load diff
633
Pico/Draw2.c
Normal file
633
Pico/Draw2.c
Normal file
|
@ -0,0 +1,633 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
// this is a frame-based renderer, alternative to Dave's line based which is in Draw.c
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
#include <assert.h>
|
||||
#ifndef __GNUC__
|
||||
#pragma warning (disable:4706) // Disable assignment within conditional
|
||||
#endif
|
||||
|
||||
// port_config.h include must define these 2 defines:
|
||||
// #define START_ROW 1 // which row of tiles to start rendering at?
|
||||
// #define END_ROW 27 // ..end
|
||||
// one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
|
||||
|
||||
#define TILE_ROWS END_ROW-START_ROW
|
||||
|
||||
#define USE_CACHE
|
||||
|
||||
|
||||
extern unsigned char *framebuff; // in format (8+320)x(8+224+8) (eights for borders)
|
||||
int currpri = 0;
|
||||
|
||||
static int HighCacheA[41*(TILE_ROWS+1)+1+1]; // caches for high layers
|
||||
static int HighCacheB[41*(TILE_ROWS+1)+1+1];
|
||||
|
||||
unsigned short *PicoCramHigh=Pico.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
|
||||
void (*PicoPrepareCram)()=0; // prepares PicoCramHigh for renderer to use
|
||||
|
||||
|
||||
// stuff available in asm:
|
||||
#ifdef _ASM_DRAW_C
|
||||
void BackFillFull(int reg7);
|
||||
void DrawLayerFull(int plane, int *hcache, int planestart, int planeend);
|
||||
void DrawTilesFromCacheF(int *hc);
|
||||
void DrawWindowFull(int start, int end, int prio);
|
||||
void DrawSpriteFull(unsigned int *sprite);
|
||||
#else
|
||||
|
||||
|
||||
static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal)
|
||||
{
|
||||
unsigned int pack=0; unsigned int t=0, blank = 1;
|
||||
int i;
|
||||
|
||||
for(i=8; i; i--, addr+=2, pd += 320+8) {
|
||||
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
|
||||
if(!pack) continue;
|
||||
|
||||
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
|
||||
t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);
|
||||
t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);
|
||||
t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal);
|
||||
t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);
|
||||
t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);
|
||||
t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);
|
||||
t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);
|
||||
blank = 0;
|
||||
}
|
||||
|
||||
return blank; // Tile blank?
|
||||
}
|
||||
|
||||
static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal)
|
||||
{
|
||||
unsigned int pack=0; unsigned int t=0, blank = 1;
|
||||
int i;
|
||||
|
||||
for(i=8; i; i--, addr+=2, pd += 320+8) {
|
||||
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
|
||||
if(!pack) continue;
|
||||
|
||||
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
|
||||
t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);
|
||||
t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);
|
||||
t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);
|
||||
t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal);
|
||||
t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);
|
||||
t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);
|
||||
t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);
|
||||
blank = 0;
|
||||
}
|
||||
return blank; // Tile blank?
|
||||
}
|
||||
|
||||
static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal)
|
||||
{
|
||||
unsigned int pack=0; unsigned int t=0, blank = 1;
|
||||
int i;
|
||||
|
||||
addr+=14;
|
||||
for(i=8; i; i--, addr-=2, pd += 320+8) {
|
||||
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
|
||||
if(!pack) continue;
|
||||
|
||||
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
|
||||
t=pack&0x00000f00; if (t) pd[1]=(unsigned char)((t>> 8)|pal);
|
||||
t=pack&0x000000f0; if (t) pd[2]=(unsigned char)((t>> 4)|pal);
|
||||
t=pack&0x0000000f; if (t) pd[3]=(unsigned char)((t )|pal);
|
||||
t=pack&0xf0000000; if (t) pd[4]=(unsigned char)((t>>28)|pal);
|
||||
t=pack&0x0f000000; if (t) pd[5]=(unsigned char)((t>>24)|pal);
|
||||
t=pack&0x00f00000; if (t) pd[6]=(unsigned char)((t>>20)|pal);
|
||||
t=pack&0x000f0000; if (t) pd[7]=(unsigned char)((t>>16)|pal);
|
||||
blank = 0;
|
||||
}
|
||||
|
||||
return blank; // Tile blank?
|
||||
}
|
||||
|
||||
static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal)
|
||||
{
|
||||
unsigned int pack=0; unsigned int t=0, blank = 1;
|
||||
int i;
|
||||
|
||||
addr+=14;
|
||||
for(i=8; i; i--, addr-=2, pd += 320+8) {
|
||||
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
|
||||
if(!pack) continue;
|
||||
|
||||
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
|
||||
t=pack&0x00f00000; if (t) pd[1]=(unsigned char)((t>>20)|pal);
|
||||
t=pack&0x0f000000; if (t) pd[2]=(unsigned char)((t>>24)|pal);
|
||||
t=pack&0xf0000000; if (t) pd[3]=(unsigned char)((t>>28)|pal);
|
||||
t=pack&0x0000000f; if (t) pd[4]=(unsigned char)((t )|pal);
|
||||
t=pack&0x000000f0; if (t) pd[5]=(unsigned char)((t>> 4)|pal);
|
||||
t=pack&0x00000f00; if (t) pd[6]=(unsigned char)((t>> 8)|pal);
|
||||
t=pack&0x0000f000; if (t) pd[7]=(unsigned char)((t>>12)|pal);
|
||||
blank = 0;
|
||||
}
|
||||
return blank; // Tile blank?
|
||||
}
|
||||
|
||||
|
||||
// start: (tile_start<<16)|row_start, end: [same]
|
||||
static void DrawWindowFull(int start, int end, int prio)
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int nametab, nametab_step, trow, tilex, blank=-1, code;
|
||||
unsigned char *scrpos = framebuff;
|
||||
int tile_start, tile_end; // in cells
|
||||
|
||||
// parse ranges
|
||||
tile_start = start>>16;
|
||||
tile_end = end>>16;
|
||||
start = start<<16>>16;
|
||||
end = end<<16>>16;
|
||||
|
||||
// Find name table line:
|
||||
if (pvid->reg[12]&1)
|
||||
{
|
||||
nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode
|
||||
nametab_step = 1<<6;
|
||||
}
|
||||
else
|
||||
{
|
||||
nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode
|
||||
nametab_step = 1<<5;
|
||||
}
|
||||
nametab += nametab_step*start;
|
||||
|
||||
// check priority
|
||||
code=Pico.vram[nametab+tile_start];
|
||||
if ((code>>15) != prio) return; // hack: just assume that whole window uses same priority
|
||||
|
||||
scrpos+=8*328+8;
|
||||
scrpos+=8*328*(start-START_ROW);
|
||||
|
||||
// do a window until we reach planestart row
|
||||
for(trow = start; trow < end; trow++, nametab+=nametab_step) { // current tile row
|
||||
for (tilex=tile_start; tilex<tile_end; tilex++)
|
||||
{
|
||||
int code,addr,zero=0;
|
||||
// unsigned short *pal=NULL;
|
||||
unsigned char pal;
|
||||
|
||||
code=Pico.vram[nametab+tilex];
|
||||
if (code==blank) continue;
|
||||
|
||||
// Get tile address/2:
|
||||
addr=(code&0x7ff)<<4;
|
||||
|
||||
// pal=PicoCramHigh+((code>>9)&0x30);
|
||||
pal=(unsigned char)((code>>9)&0x30);
|
||||
|
||||
switch((code>>11)&3) {
|
||||
case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal); break;
|
||||
case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal); break;
|
||||
case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal); break;
|
||||
case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal); break;
|
||||
}
|
||||
if(zero) blank=code; // We know this tile is blank now
|
||||
}
|
||||
|
||||
scrpos += 328*8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps
|
||||
int width, height, ymask, htab;
|
||||
int nametab, hscroll=0, vscroll, cells;
|
||||
unsigned char *scrpos;
|
||||
int blank=-1, xmask, nametab_row, trow;
|
||||
|
||||
// parse ranges
|
||||
cells = (planeend>>16)-(planestart>>16);
|
||||
planestart = planestart<<16>>16;
|
||||
planeend = planeend<<16>>16;
|
||||
|
||||
// Work out the Tiles to draw
|
||||
|
||||
htab=pvid->reg[13]<<9; // Horizontal scroll table address
|
||||
// if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line
|
||||
// if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile
|
||||
htab+=plane; // A or B
|
||||
|
||||
if(!(pvid->reg[11]&3)) { // full screen scroll
|
||||
// Get horizontal scroll value
|
||||
hscroll=Pico.vram[htab&0x7fff];
|
||||
htab = 0; // this marks that we don't have to update scroll value
|
||||
}
|
||||
|
||||
// Work out the name table size: 32 64 or 128 tiles (0-3)
|
||||
width=pvid->reg[16];
|
||||
height=(width>>4)&3; width&=3;
|
||||
|
||||
xmask=(1<<shift[width ])-1; // X Mask in tiles
|
||||
ymask=(height<<5)|0x1f; // Y Mask in tiles
|
||||
if(width == 1) ymask&=0x3f;
|
||||
else if(width>1) ymask =0x1f;
|
||||
|
||||
// Find name table:
|
||||
if (plane==0) nametab=(pvid->reg[2]&0x38)<< 9; // A
|
||||
else nametab=(pvid->reg[4]&0x07)<<12; // B
|
||||
|
||||
scrpos = framebuff;
|
||||
scrpos+=8*328*(planestart-START_ROW);
|
||||
|
||||
// Get vertical scroll value:
|
||||
vscroll=Pico.vsram[plane]&0x1ff;
|
||||
scrpos+=(8-(vscroll&7))*328;
|
||||
if(vscroll&7) planeend++; // we have vertically clipped tiles due to vscroll, so we need 1 more row
|
||||
|
||||
*hcache++ = 8-(vscroll&7); // push y-offset to tilecache
|
||||
|
||||
|
||||
for(trow = planestart; trow < planeend; trow++) { // current tile row
|
||||
int cellc=cells,tilex,dx;
|
||||
|
||||
// Find the tile row in the name table
|
||||
//ts.line=(vscroll+Scanline)&ymask;
|
||||
//ts.nametab+=(ts.line>>3)<<shift[width];
|
||||
nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row
|
||||
|
||||
// update hscroll if needed
|
||||
if(htab) {
|
||||
int htaddr=htab+(trow<<4);
|
||||
if(trow) htaddr-=(vscroll&7)<<1;
|
||||
hscroll=Pico.vram[htaddr&0x7fff];
|
||||
}
|
||||
|
||||
// Draw tiles across screen:
|
||||
tilex=(-hscroll)>>3;
|
||||
dx=((hscroll-1)&7)+1;
|
||||
if(dx != 8) cellc++; // have hscroll, do more cells
|
||||
|
||||
for (; cellc; dx+=8,tilex++,cellc--)
|
||||
{
|
||||
int code=0,addr=0,zero=0;
|
||||
// unsigned short *pal=NULL;
|
||||
unsigned char pal;
|
||||
|
||||
code=Pico.vram[nametab_row+(tilex&xmask)];
|
||||
if (code==blank) continue;
|
||||
|
||||
#ifdef USE_CACHE
|
||||
if (code>>15) { // high priority tile
|
||||
*hcache++ = code|(dx<<16)|(trow<<27); // cache it
|
||||
#else
|
||||
if ((code>>15) != currpri) {
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get tile address/2:
|
||||
addr=(code&0x7ff)<<4;
|
||||
|
||||
// pal=PicoCramHigh+((code>>9)&0x30);
|
||||
pal=(unsigned char)((code>>9)&0x30);
|
||||
|
||||
switch((code>>11)&3) {
|
||||
case 0: zero=TileXnormYnorm(scrpos+dx,addr,pal); break;
|
||||
case 1: zero=TileXflipYnorm(scrpos+dx,addr,pal); break;
|
||||
case 2: zero=TileXnormYflip(scrpos+dx,addr,pal); break;
|
||||
case 3: zero=TileXflipYflip(scrpos+dx,addr,pal); break;
|
||||
}
|
||||
if(zero) blank=code; // We know this tile is blank now
|
||||
}
|
||||
|
||||
scrpos += 328*8;
|
||||
}
|
||||
|
||||
*hcache = 0; // terminate cache
|
||||
}
|
||||
|
||||
|
||||
static void DrawTilesFromCacheF(int *hc)
|
||||
{
|
||||
int code, addr, zero = 0;
|
||||
unsigned int prevy=0xFFFFFFFF;
|
||||
// unsigned short *pal;
|
||||
unsigned char pal;
|
||||
short blank=-1; // The tile we know is blank
|
||||
unsigned char *scrpos = framebuff, *pd = 0;
|
||||
|
||||
// *hcache++ = code|(dx<<16)|(trow<<27); // cache it
|
||||
scrpos+=(*hc++)*328 - START_ROW*328*8;
|
||||
|
||||
while((code=*hc++)) {
|
||||
if((short)code == blank) continue;
|
||||
|
||||
// y pos
|
||||
if(((unsigned)code>>27) != prevy) {
|
||||
prevy = (unsigned)code>>27;
|
||||
pd = scrpos + prevy*328*8;
|
||||
}
|
||||
|
||||
// Get tile address/2:
|
||||
addr=(code&0x7ff)<<4;
|
||||
// pal=PicoCramHigh+((code>>9)&0x30);
|
||||
pal=(unsigned char)((code>>9)&0x30);
|
||||
|
||||
switch((code>>11)&3) {
|
||||
case 0: zero=TileXnormYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
|
||||
case 1: zero=TileXflipYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
|
||||
case 2: zero=TileXnormYflip(pd+((code>>16)&0x1ff),addr,pal); break;
|
||||
case 3: zero=TileXflipYflip(pd+((code>>16)&0x1ff),addr,pal); break;
|
||||
}
|
||||
|
||||
if(zero) blank=(short)code;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sx and sy are coords of virtual screen with 8pix borders on top and on left
|
||||
static void DrawSpriteFull(unsigned int *sprite)
|
||||
{
|
||||
int width=0,height=0;
|
||||
// unsigned short *pal=NULL;
|
||||
unsigned char pal;
|
||||
int tile,code,tdeltax,tdeltay;
|
||||
unsigned char *scrpos;
|
||||
int sx, sy;
|
||||
|
||||
sy=sprite[0];
|
||||
height=sy>>24;
|
||||
sy=(sy&0x1ff)-0x78; // Y
|
||||
width=(height>>2)&3; height&=3;
|
||||
width++; height++; // Width and height in tiles
|
||||
|
||||
code=sprite[1];
|
||||
sx=((code>>16)&0x1ff)-0x78; // X
|
||||
|
||||
tile=code&0x7ff; // Tile number
|
||||
tdeltax=height; // Delta to increase tile by going right
|
||||
tdeltay=1; // Delta to increase tile by going down
|
||||
if (code&0x0800) { tdeltax=-tdeltax; tile+=height*(width-1); } // Flip X
|
||||
if (code&0x1000) { tdeltay=-tdeltay; tile+=height-1; } // Flip Y
|
||||
|
||||
//delta<<=4; // Delta of address
|
||||
// pal=PicoCramHigh+((code>>9)&0x30); // Get palette pointer
|
||||
pal=(unsigned char)((code>>9)&0x30);
|
||||
|
||||
// goto first vertically visible tile
|
||||
while(sy <= START_ROW*8) { sy+=8; tile+=tdeltay; height--; }
|
||||
|
||||
scrpos = framebuff;
|
||||
scrpos+=(sy-START_ROW*8)*328;
|
||||
|
||||
for (; height > 0; height--, sy+=8, tile+=tdeltay)
|
||||
{
|
||||
int w = width, x=sx, t=tile;
|
||||
|
||||
if(sy >= END_ROW*8+8) return; // offscreen
|
||||
|
||||
for (; w; w--,x+=8,t+=tdeltax)
|
||||
{
|
||||
if(x<=0) continue;
|
||||
if(x>=328) break; // Offscreen
|
||||
|
||||
t&=0x7fff; // Clip tile address
|
||||
switch((code>>11)&3) {
|
||||
case 0: TileXnormYnorm(scrpos+x,t<<4,pal); break;
|
||||
case 1: TileXflipYnorm(scrpos+x,t<<4,pal); break;
|
||||
case 2: TileXnormYflip(scrpos+x,t<<4,pal); break;
|
||||
case 3: TileXflipYflip(scrpos+x,t<<4,pal); break;
|
||||
}
|
||||
}
|
||||
|
||||
scrpos+=8*328;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void DrawAllSpritesFull(int prio, int maxwidth)
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int table=0,maskrange=0;
|
||||
int i,u,link=0;
|
||||
unsigned int *sprites[80]; // Sprites
|
||||
int y_min=START_ROW*8, y_max=END_ROW*8; // for a simple sprite masking
|
||||
|
||||
table=pvid->reg[5]&0x7f;
|
||||
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
|
||||
table<<=8; // Get sprite table address/2
|
||||
|
||||
for (i=u=0; u < 80; u++)
|
||||
{
|
||||
unsigned int *sprite=NULL;
|
||||
int code, code2, sx, sy, height;
|
||||
|
||||
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
|
||||
|
||||
// get sprite info
|
||||
code = sprite[0];
|
||||
|
||||
// check if it is not hidden vertically
|
||||
sy = (code&0x1ff)-0x80;
|
||||
height = (((code>>24)&3)+1)<<3;
|
||||
if(sy+height <= y_min || sy > y_max) goto nextsprite;
|
||||
|
||||
// masking sprite?
|
||||
code2=sprite[1];
|
||||
sx = (code2>>16)&0x1ff;
|
||||
if(!sx) {
|
||||
int to = sy+height; // sy ~ from
|
||||
if(maskrange) {
|
||||
// try to merge with previous range
|
||||
if((maskrange>>16)+1 >= sy && (maskrange>>16) <= to && (maskrange&0xffff) < sy) sy = (maskrange&0xffff);
|
||||
else if((maskrange&0xffff)-1 <= to && (maskrange&0xffff) >= sy && (maskrange>>16) > to) to = (maskrange>>16);
|
||||
}
|
||||
// support only very simple masking (top and bottom of screen)
|
||||
if(sy <= y_min && to+1 > y_min) y_min = to+1;
|
||||
else if(to >= y_max && sy-1 < y_max) y_max = sy-1;
|
||||
else maskrange=sy|(to<<16);
|
||||
|
||||
goto nextsprite;
|
||||
}
|
||||
|
||||
// priority
|
||||
if(((code2>>15)&1) != prio) goto nextsprite; // wrong priority
|
||||
|
||||
// check if sprite is not hidden horizontally
|
||||
sx -= 0x78; // Get X coordinate + 8
|
||||
if(sx <= -8*3 || sx >= maxwidth) goto nextsprite;
|
||||
|
||||
// sprite is good, save it's index
|
||||
sprites[i++]=sprite;
|
||||
|
||||
nextsprite:
|
||||
// Find next sprite
|
||||
link=(code>>16)&0x7f;
|
||||
if(!link) break; // End of sprites
|
||||
}
|
||||
|
||||
// Go through sprites backwards:
|
||||
for (i-- ;i>=0; i--)
|
||||
{
|
||||
DrawSpriteFull(sprites[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _ASM_DRAW_C
|
||||
static void BackFillFull(int reg7)
|
||||
{
|
||||
unsigned int back, i;
|
||||
unsigned int *p=(unsigned int *)framebuff;
|
||||
|
||||
// Start with a background color:
|
||||
// back=PicoCramHigh[reg7&0x3f];
|
||||
back=reg7&0x3f;
|
||||
back|=back<<8;
|
||||
back|=back<<16;
|
||||
|
||||
for(i = (8+320)*(8+(END_ROW-START_ROW)*8)/16; i; i--) {
|
||||
*p++ = back; // do 16 pixels per iteration
|
||||
*p++ = back;
|
||||
*p++ = back;
|
||||
*p++ = back;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DrawDisplayFull()
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int win, edge=0, hvwin=0; // LSb->MSb: hwin&plane, vwin&plane, full
|
||||
int planestart=START_ROW, planeend=END_ROW; // plane A start/end when window shares display with plane A (in tile rows or columns)
|
||||
int winstart=START_ROW, winend=END_ROW; // same for window
|
||||
int maxw, maxcolc; // max width and col cells
|
||||
|
||||
if(pvid->reg[12]&1) {
|
||||
maxw = 328; maxcolc = 40;
|
||||
} else {
|
||||
maxw = 264; maxcolc = 32;
|
||||
}
|
||||
|
||||
// horizontal window?
|
||||
if((win=pvid->reg[0x12])) {
|
||||
hvwin=1; // hwindow shares display with plane A
|
||||
edge=win&0x1f;
|
||||
if(win == 0x80) {
|
||||
// fullscreen window
|
||||
hvwin=4;
|
||||
} else if(win < 0x80) {
|
||||
// window on the top
|
||||
if(edge <= START_ROW) hvwin=0; // window not visible in our drawing region
|
||||
else if(edge >= END_ROW) hvwin=4;
|
||||
else planestart = winend = edge;
|
||||
} else if(win > 0x80) {
|
||||
// window at the bottom
|
||||
if(edge >= END_ROW) hvwin=0;
|
||||
else planeend = winstart = edge;
|
||||
}
|
||||
}
|
||||
|
||||
// check for vertical window, but only if win is not fullscreen
|
||||
if(hvwin != 4) {
|
||||
win=pvid->reg[0x11];
|
||||
edge=win&0x1f;
|
||||
if (win&0x80) {
|
||||
if(!edge) hvwin=4;
|
||||
else if(edge < (maxcolc>>1)) {
|
||||
// window is on the right
|
||||
hvwin|=2;
|
||||
planeend|=edge<<17;
|
||||
winstart|=edge<<17;
|
||||
winend|=maxcolc<<16;
|
||||
}
|
||||
} else {
|
||||
if(edge >= (maxcolc>>1)) hvwin=4;
|
||||
else if(edge) {
|
||||
// window is on the left
|
||||
hvwin|=2;
|
||||
winend|=edge<<17;
|
||||
planestart|=edge<<17;
|
||||
planeend|=maxcolc<<16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(hvwin==1) { winend|=maxcolc<<16; planeend|=maxcolc<<16; }
|
||||
|
||||
currpri = 0;
|
||||
DrawLayerFull(1, HighCacheB, START_ROW, (maxcolc<<16)|END_ROW);
|
||||
switch(hvwin) {
|
||||
case 4:
|
||||
// fullscreen window
|
||||
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 0);
|
||||
HighCacheA[1] = 0;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// we have plane A and both v and h windows
|
||||
DrawLayerFull(0, HighCacheA, planestart, planeend);
|
||||
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0); // h
|
||||
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 0); // v
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 1:
|
||||
// both window and plane A visible, window is vertical XOR horizontal
|
||||
DrawLayerFull(0, HighCacheA, planestart, planeend);
|
||||
DrawWindowFull(winstart, winend, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
// fullscreen plane A
|
||||
DrawLayerFull(0, HighCacheA, START_ROW, (maxcolc<<16)|END_ROW);
|
||||
break;
|
||||
}
|
||||
DrawAllSpritesFull(0, maxw);
|
||||
|
||||
#ifdef USE_CACHE
|
||||
if(HighCacheB[1]) DrawTilesFromCacheF(HighCacheB);
|
||||
if(HighCacheA[1]) DrawTilesFromCacheF(HighCacheA);
|
||||
switch(hvwin) {
|
||||
case 4:
|
||||
// fullscreen window
|
||||
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 1);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// we have plane A and both v and h windows
|
||||
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1); // h
|
||||
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 1); // v
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 1:
|
||||
// both window and plane A visible, window is vertical XOR horizontal
|
||||
DrawWindowFull(winstart, winend, 1);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
currpri = 1;
|
||||
// TODO
|
||||
#endif
|
||||
DrawAllSpritesFull(1, maxw);
|
||||
}
|
||||
|
||||
|
||||
void PicoFrameFull()
|
||||
{
|
||||
// prepare cram?
|
||||
if(PicoPrepareCram) PicoPrepareCram();
|
||||
|
||||
// Draw screen:
|
||||
BackFillFull(Pico.video.reg[7]);
|
||||
if (Pico.video.reg[1]&0x40) DrawDisplayFull();
|
||||
}
|
||||
|
928
Pico/Draw2.s
Normal file
928
Pico/Draw2.s
Normal file
|
@ -0,0 +1,928 @@
|
|||
@ assembly optimized versions of most funtions from draw2.c
|
||||
@ this is highly specialized, be careful if changing related C code!
|
||||
|
||||
@ (c) Copyright 2006, notaz
|
||||
@ All Rights Reserved
|
||||
|
||||
|
||||
.extern Pico
|
||||
.extern framebuff
|
||||
|
||||
@ define these constants in your include file:
|
||||
@ .equiv START_ROW, 1
|
||||
@ .equiv END_ROW, 27
|
||||
@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
|
||||
.include "port_config.s"
|
||||
|
||||
|
||||
.global BackFillFull @ int reg7
|
||||
|
||||
BackFillFull:
|
||||
stmfd sp!, {r4-r9,lr}
|
||||
|
||||
ldr lr, =framebuff @ lr=framebuff
|
||||
ldr lr, [lr]
|
||||
add lr, lr, #328*8
|
||||
|
||||
mov r0, r0, lsl #26
|
||||
mov r0, r0, lsr #26
|
||||
orr r0, r0, r0, lsl #8
|
||||
orr r0, r0, r0, lsl #16
|
||||
|
||||
mov r1, r0 @ 25 opcodes wasted?
|
||||
mov r2, r0
|
||||
mov r3, r0
|
||||
mov r4, r0
|
||||
mov r5, r0
|
||||
mov r6, r0
|
||||
mov r7, r0
|
||||
mov r8, r0
|
||||
mov r9, r0
|
||||
|
||||
mov r12, #(END_ROW-START_ROW)*8
|
||||
|
||||
@ go go go!
|
||||
.bff_loop:
|
||||
add lr, lr, #8
|
||||
subs r12, r12, #1
|
||||
|
||||
stmia lr!, {r0-r9} @ 10*4*8
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
stmia lr!, {r0-r9}
|
||||
|
||||
bne .bff_loop
|
||||
|
||||
ldmfd sp!, {r4-r9,r12}
|
||||
bx r12
|
||||
|
||||
.pool
|
||||
|
||||
@ -------- some macros --------
|
||||
|
||||
|
||||
@ helper
|
||||
@ TileLineSinglecol (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: pixels8_old
|
||||
.macro TileLineSinglecol notsinglecol=0
|
||||
and r2, r2, #0xf @ #0x0000000f
|
||||
.if !\notsinglecol
|
||||
cmp r2, r0, lsr #28 @ if these don't match,
|
||||
bicne r9, r9, #2 @ it is a sign that whole tile is not singlecolor (only it's lines may be)
|
||||
.endif
|
||||
orr r4, r3, r2
|
||||
orr r4, r4, r4, lsl #8
|
||||
|
||||
tst r1, #1 @ not aligned?
|
||||
strneb r4, [r1], #1
|
||||
streqh r4, [r1], #2
|
||||
strh r4, [r1], #2
|
||||
strh r4, [r1], #2
|
||||
strh r4, [r1], #2
|
||||
strneb r4, [r1], #1 @ have a remaining unaligned pixel?
|
||||
sub r1, r1, #8
|
||||
.if !\notsinglecol
|
||||
mov r0, #0xf
|
||||
orr r0, r0, r2, lsl #28 @ we will need the old palindex later
|
||||
.endif
|
||||
.endm
|
||||
|
||||
@ TileNorm (r1=pdest, r2=pixels8, r3=pal) r0,r4: scratch
|
||||
.macro TileLineNorm
|
||||
ands r4, r0, r2, lsr #12 @ #0x0000f000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1]
|
||||
ands r4, r0, r2, lsr #8 @ #0x00000f00
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#1]
|
||||
ands r4, r0, r2, lsr #4 @ #0x000000f0
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#2]
|
||||
ands r4, r0, r2 @ #0x0000000f
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#3]
|
||||
ands r4, r0, r2, lsr #28 @ #0xf0000000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#4]
|
||||
ands r4, r0, r2, lsr #24 @ #0x0f000000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#5]
|
||||
ands r4, r0, r2, lsr #20 @ #0x00f00000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#6]
|
||||
ands r4, r0, r2, lsr #16 @ #0x000f0000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#7]
|
||||
.endm
|
||||
|
||||
@ TileFlip (r1=pdest, r2=pixels8, r3=pal) r0,r4: scratch
|
||||
.macro TileLineFlip
|
||||
ands r4, r0, r2, lsr #16 @ #0x000f0000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1]
|
||||
ands r4, r0, r2, lsr #20 @ #0x00f00000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#1]
|
||||
ands r4, r0, r2, lsr #24 @ #0x0f000000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#2]
|
||||
ands r4, r0, r2, lsr #28 @ #0xf0000000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#3]
|
||||
ands r4, r0, r2 @ #0x0000000f
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#4]
|
||||
ands r4, r0, r2, lsr #4 @ #0x000000f0
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#5]
|
||||
ands r4, r0, r2, lsr #8 @ #0x00000f00
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#6]
|
||||
ands r4, r0, r2, lsr #12 @ #0x0000f000
|
||||
orrne r4, r3, r4
|
||||
strneb r4, [r1,#7]
|
||||
.endm
|
||||
|
||||
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
|
||||
.macro Tile hflip vflip
|
||||
mov r7, r9, lsl #13 @ r9=code<<8; addr=(code&0x7ff)<<4;
|
||||
add r7, r10, r7, lsr #16
|
||||
orr r9, r9, #3 @ emptytile=singlecolor=1, r9 must be <code_16> 00000xxx
|
||||
.if \vflip
|
||||
@ we read tilecodes in reverse order if we have vflip
|
||||
add r7, r7, #8*4
|
||||
.endif
|
||||
@ loop through 8 lines
|
||||
orr r9, r9, #(7<<24)
|
||||
b 1f @ loop_enter
|
||||
|
||||
0: @ singlecol_loop
|
||||
subs r9, r9, #(1<<24)
|
||||
add r1, r1, #328 @ set pointer to next line
|
||||
bmi 8f @ loop_exit with r0 restore
|
||||
1:
|
||||
.if \vflip
|
||||
ldr r2, [r7, #-4]! @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
|
||||
.else
|
||||
ldr r2, [r7], #4
|
||||
.endif
|
||||
tst r2, r2
|
||||
beq 2f @ empty line
|
||||
bic r9, r9, #1
|
||||
cmp r2, r2, ror #4
|
||||
bne 3f @ not singlecolor
|
||||
TileLineSinglecol
|
||||
b 0b
|
||||
|
||||
2:
|
||||
bic r9, r9, #2
|
||||
2: @ empty_loop
|
||||
subs r9, r9, #(1<<24)
|
||||
add r1, r1, #328 @ set pointer to next line
|
||||
bmi 8f @ loop_exit with r0 restore
|
||||
.if \vflip
|
||||
ldr r2, [r7, #-4]! @ next pack
|
||||
.else
|
||||
ldr r2, [r7], #4
|
||||
.endif
|
||||
mov r0, #0xf @ singlecol_loop might have messed r0
|
||||
tst r2, r2
|
||||
beq 2b
|
||||
|
||||
bic r9, r9, #3 @ if we are here, it means we have empty and not empty line
|
||||
b 5f
|
||||
|
||||
3: @ not empty, not singlecol
|
||||
mov r0, #0xf
|
||||
bic r9, r9, #3
|
||||
b 6f
|
||||
|
||||
4: @ not empty, not singlecol loop
|
||||
subs r9, r9, #(1<<24)
|
||||
add r1, r1, #328 @ set pointer to next line
|
||||
bmi 9f @ loop_exit
|
||||
.if \vflip
|
||||
ldr r2, [r7, #-4]! @ next pack
|
||||
.else
|
||||
ldr r2, [r7], #4
|
||||
.endif
|
||||
tst r2, r2
|
||||
beq 4b @ empty line
|
||||
5:
|
||||
cmp r2, r2, ror #4
|
||||
beq 7f @ singlecolor line
|
||||
6:
|
||||
.if \hflip
|
||||
TileLineFlip
|
||||
.else
|
||||
TileLineNorm
|
||||
.endif
|
||||
b 4b
|
||||
7:
|
||||
TileLineSinglecol 1
|
||||
b 4b
|
||||
|
||||
8:
|
||||
mov r0, #0xf
|
||||
9: @ loop_exit
|
||||
add r9, r9, #(1<<24) @ fix r9
|
||||
sub r1, r1, #328*8 @ restore pdest pointer
|
||||
.endm
|
||||
|
||||
|
||||
@ TileLineSinglecolAl (r1=pdest, r4,r7=color)
|
||||
.macro TileLineSinglecolAl0
|
||||
stmia r1!, {r4,r7}
|
||||
add r1, r1, #320
|
||||
.endm
|
||||
|
||||
.macro TileLineSinglecolAl1
|
||||
strb r4, [r1], #1
|
||||
strh r4, [r1], #2
|
||||
str r4, [r1], #4
|
||||
strb r4, [r1], #1+320
|
||||
@ add r1, r1, #320
|
||||
.endm
|
||||
|
||||
.macro TileLineSinglecolAl2
|
||||
strh r4, [r1], #2
|
||||
str r4, [r1], #4
|
||||
strh r4, [r1], #2
|
||||
add r1, r1, #320
|
||||
.endm
|
||||
|
||||
.macro TileLineSinglecolAl3
|
||||
strb r4, [r1], #1
|
||||
str r4, [r1], #4
|
||||
strh r4, [r1], #2
|
||||
strb r4, [r1], #1+320
|
||||
@ add r1, r1, #320
|
||||
.endm
|
||||
|
||||
@ TileSinglecol (r1=pdest, r2=pixels8, r3=pal) r4,r7: scratch, r0=0xf
|
||||
@ kaligned==1, if dest is always aligned
|
||||
.macro TileSinglecol kaligned=0
|
||||
and r4, r2, #0xf @ we assume we have good r2 from previous time
|
||||
orr r4, r4, r3
|
||||
orr r4, r4, r4, lsl #8
|
||||
orr r4, r4, r4, lsl #16
|
||||
mov r7, r4
|
||||
|
||||
.if !\kaligned
|
||||
tst r1, #2 @ not aligned?
|
||||
bne 2f
|
||||
tst r1, #1
|
||||
bne 1f
|
||||
.endif
|
||||
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
TileLineSinglecolAl0
|
||||
|
||||
.if !\kaligned
|
||||
b 4f
|
||||
1:
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
TileLineSinglecolAl1
|
||||
b 4f
|
||||
|
||||
2:
|
||||
tst r1, #1
|
||||
bne 3f
|
||||
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
TileLineSinglecolAl2
|
||||
b 4f
|
||||
|
||||
3:
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
TileLineSinglecolAl3
|
||||
|
||||
4:
|
||||
.endif
|
||||
sub r1, r1, #328*8 @ restore pdest pointer
|
||||
.endm
|
||||
|
||||
|
||||
|
||||
@ DrawLayerTiles(*hcache, *scrpos, (cells<<24)|(nametab<<9)|(vscroll&0x3ff)<<11|(shift[width]<<8)|planeend, (ymask<<24)|(planestart<<16)|[htab||hscroll]
|
||||
|
||||
@static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
|
||||
|
||||
.global DrawLayerFull
|
||||
|
||||
DrawLayerFull:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
|
||||
mov r6, r1 @ hcache
|
||||
|
||||
sub lr, r3, r2
|
||||
and lr, lr, #0x00ff0000 @ lr=cells
|
||||
|
||||
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
|
||||
|
||||
ldr r11, =(Pico+0x22228) @ Pico.video
|
||||
ldrb r5, [r11, #13] @ pvid->reg[13]
|
||||
mov r5, r5, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords)
|
||||
add r5, r5, r0, lsl #1 @ htab+=plane
|
||||
bic r5, r5, #0x00ff0000 @ just in case
|
||||
|
||||
ldrb r7, [r11, #11]
|
||||
tst r7, #3 @ full screen scroll? (if ==0)
|
||||
ldreqh r5, [r10, r5]
|
||||
biceq r5, r5, #0x0000fc00 @ r5=hscroll (0-0x3ff)
|
||||
movne r5, r5, lsr #1
|
||||
orrne r5, r5, #0x8000 @ this marks that we have htab pointer, not hscroll here
|
||||
|
||||
ldrb r7, [r11, #16] @ ??hh??ww
|
||||
and r8, r7, #3
|
||||
|
||||
orr r5, r5, r7, lsl #1+24
|
||||
orr r5, r5, #0x1f000000
|
||||
cmp r8, #1
|
||||
biclt r5, r5, #0x80000000
|
||||
biceq r5, r5, #0xc0000000
|
||||
bicgt r5, r5, #0xe0000000
|
||||
|
||||
mov r9, r2, lsl #24
|
||||
orr r5, r5, r9, lsr #8 @ r5=(ymask<<24)|(trow<<16)|[htab||hscroll]
|
||||
|
||||
add r4, r8, #5
|
||||
cmp r4, #7
|
||||
subge r4, r4, #1 @ r4=shift[width] (5,6,6,7)
|
||||
|
||||
orr lr, lr, r4
|
||||
orr lr, lr, r3, lsl #24 @ lr=(planeend<<24)|(cells<<16)|shift[width]
|
||||
|
||||
@ calculate xmask:
|
||||
mov r8, r8, lsl #24+5
|
||||
orr r8, r8, #0x1f000000
|
||||
|
||||
@ Find name table:
|
||||
tst r0, r0
|
||||
ldreqb r4, [r11, #2]
|
||||
moveq r4, r4, lsr #3
|
||||
ldrneb r4, [r11, #4]
|
||||
and r4, r4, #7
|
||||
orr lr, lr, r4, lsl #13 @ lr|=nametab_bits{3}<<13
|
||||
|
||||
ldr r11, =framebuff @ r11=framebuff
|
||||
ldr r11, [r11]
|
||||
sub r4, r9, #(START_ROW<<24)
|
||||
mov r4, r4, asr #24
|
||||
mov r7, #328*8
|
||||
mla r11, r4, r7, r11 @ scrpos+=8*328*(planestart-START_ROW);
|
||||
|
||||
@ Get vertical scroll value:
|
||||
add r7, r10, #0x012000
|
||||
add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180)
|
||||
ldr r7, [r7]
|
||||
tst r0, r0
|
||||
moveq r7, r7, lsl #22
|
||||
movne r7, r7, lsl #6
|
||||
mov r7, r7, lsr #22 @ r7=vscroll (10 bits)
|
||||
|
||||
orr lr, lr, r7, lsl #3
|
||||
mov lr, lr, ror #24 @ packed: cccccccc nnnvvvvv vvvvvsss pppppppp: cells, nametab, vscroll, shift[width], planeend
|
||||
|
||||
ands r7, r7, #7
|
||||
addne lr, lr, #1 @ we have vertically clipped tiles due to vscroll, so we need 1 more row
|
||||
|
||||
rsb r7, r7, #8
|
||||
str r7, [r6], #4 @ push y-offset to tilecache
|
||||
mov r4, #328
|
||||
mla r11, r4, r7, r11 @ scrpos+=(8-(vscroll&7))*328;
|
||||
|
||||
mov r9, #0xff000000 @ r9=(prevcode<<8)|flags: 1~tile empty, 2~tile singlecolor
|
||||
|
||||
.rtrloop_outer:
|
||||
mov r4, lr, lsl #11
|
||||
mov r4, r4, lsr #25 @ r4=vscroll>>3 (7 bits)
|
||||
add r4, r4, r5, lsr #16 @ +trow
|
||||
and r4, r4, r5, lsr #24 @ &=ymask
|
||||
mov r7, lr, lsr #8
|
||||
and r7, r7, #7 @ shift[width]
|
||||
mov r0, lr, lsr #9
|
||||
and r0, r0, #0x7000 @ nametab
|
||||
add r12,r0, r4, lsl r7 @ nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]);
|
||||
|
||||
mov r4, lr, lsr #24
|
||||
orr r12,r12,r4, lsl #23
|
||||
mov r12,r12,lsl #1 @ (nametab_row|(cells<<24)) (halfword compliant)
|
||||
|
||||
@ htab?
|
||||
tst r5, #0x8000
|
||||
moveq r7, r5, lsl #22 @ hscroll (0-3FFh)
|
||||
moveq r7, r7, lsr #22
|
||||
beq .rtr_hscroll_done
|
||||
|
||||
@ get hscroll from htab
|
||||
mov r7, r5, lsl #17
|
||||
ands r4, r5, #0x00ff0000
|
||||
add r7, r7, r4, lsl #5 @ +=trow<<4
|
||||
andne r4, lr, #0x3800
|
||||
subne r7, r7, r4, lsl #7 @ if(trow) htaddr-=(vscroll&7)<<1;
|
||||
mov r7, r7, lsr #16 @ halfwords
|
||||
ldrh r7, [r10, r7]
|
||||
|
||||
.rtr_hscroll_done:
|
||||
rsb r4, r7, #0 @ r4=tilex=(-ts->hscroll)>>3
|
||||
mov r4, r4, asr #3
|
||||
and r4, r4, #0xff
|
||||
and r8, r8, #0xff000000
|
||||
orr r8, r8, r4 @ r8=(xmask<<24)|tilex
|
||||
|
||||
sub r7, r7, #1
|
||||
and r7, r7, #7
|
||||
add r7, r7, #1 @ r7=dx=((ts->hscroll-1)&7)+1
|
||||
|
||||
cmp r7, #8
|
||||
subeq r12,r12, #0x01000000 @ we will loop cells+1 times, so loop less when there is no hscroll
|
||||
|
||||
add r1, r11, r7 @ r1=pdest
|
||||
mov r0, #0xf
|
||||
b .rtrloop_enter
|
||||
|
||||
@ r4 & r7 are scratch in this loop
|
||||
.rtrloop: @ 40-41 times
|
||||
add r1, r1, #8
|
||||
subs r12,r12, #0x01000000
|
||||
add r8, r8, #1
|
||||
bmi .rtrloop_exit
|
||||
|
||||
.rtrloop_enter:
|
||||
and r7, r8, r8, lsr #24
|
||||
add r7, r10, r7, lsl #1
|
||||
bic r4, r12, #0xff000000 @ Pico.vram[nametab_row+(tilex&xmask)];
|
||||
ldrh r7, [r7, r4] @ r7=code (int, but from unsigned, no sign extend)
|
||||
|
||||
tst r7, #0x8000
|
||||
bne .rtr_hiprio
|
||||
|
||||
cmp r7, r9, lsr #8
|
||||
bne .rtr_notsamecode
|
||||
@ we know stuff about this tile already
|
||||
tst r9, #1
|
||||
bne .rtrloop @ empty tile
|
||||
tst r9, #2
|
||||
bne .rtr_singlecolor @ singlecolor tile
|
||||
b .rtr_samecode
|
||||
|
||||
.rtr_notsamecode:
|
||||
and r4, r9, #0x600000
|
||||
mov r9, r7, lsl #8 @ remember new code
|
||||
|
||||
@ update cram
|
||||
and r7, r7, #0x6000
|
||||
mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9);
|
||||
|
||||
.rtr_samecode:
|
||||
tst r9, #0x100000 @ vflip?
|
||||
bne .rtr_vflip
|
||||
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .rtr_hflip
|
||||
|
||||
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
|
||||
Tile 0, 0
|
||||
b .rtrloop
|
||||
|
||||
.rtr_hflip:
|
||||
Tile 1, 0
|
||||
b .rtrloop
|
||||
|
||||
.rtr_vflip:
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .rtr_vflip_hflip
|
||||
|
||||
Tile 0, 1
|
||||
b .rtrloop
|
||||
|
||||
.rtr_vflip_hflip:
|
||||
Tile 1, 1
|
||||
b .rtrloop
|
||||
|
||||
.rtr_singlecolor:
|
||||
TileSinglecol
|
||||
b .rtrloop
|
||||
|
||||
.rtr_hiprio:
|
||||
@ *(*hcache)++ = code|(dx<<16)|(trow<<27);
|
||||
sub r4, r1, r11
|
||||
orr r7, r7, r4, lsl #16
|
||||
and r4, r5, #0x00ff0000
|
||||
orr r7, r7, r4, lsl #11 @ (trow<<27)
|
||||
str r7, [r6], #4 @ cache hi priority tile
|
||||
b .rtrloop
|
||||
|
||||
.rtrloop_exit:
|
||||
add r5, r5, #0x00010000
|
||||
mov r4, r5, lsl #8
|
||||
cmp r4, lr, lsl #24
|
||||
bge .rtrloop_outer_exit
|
||||
add r11, r11, #328*8
|
||||
b .rtrloop_outer
|
||||
|
||||
.rtrloop_outer_exit:
|
||||
|
||||
@ terminate cache list
|
||||
mov r0, #0
|
||||
str r0, [r6] @ save cache pointer
|
||||
|
||||
ldmfd sp!, {r4-r11,lr}
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
|
||||
|
||||
.global DrawTilesFromCacheF @ int *hc
|
||||
|
||||
DrawTilesFromCacheF:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
|
||||
mov r9, #0xff000000 @ r9=prevcode=-1
|
||||
mvn r6, #0 @ r6=prevy=-1
|
||||
|
||||
ldr r4, =framebuff @ r4=framebuff
|
||||
ldr r4, [r4]
|
||||
ldr r1, [r0], #4 @ read y offset
|
||||
mov r7, #328
|
||||
mla r1, r7, r1, r4
|
||||
sub r12, r1, #(328*8*START_ROW) @ r12=scrpos
|
||||
|
||||
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
|
||||
mov r8, r0 @ hc
|
||||
mov r0, #0xf
|
||||
|
||||
@ scratch: r4, r7
|
||||
@ *hcache++ = code|(dx<<16)|(trow<<27); // cache it
|
||||
|
||||
.dtfcf_loop:
|
||||
ldr r7, [r8], #4 @ read code
|
||||
movs r1, r7, lsr #16 @ r1=dx;
|
||||
ldmeqfd sp!, {r4-r10,pc} @ dx is never zero, this must be a terminator, return
|
||||
|
||||
@ trow changed?
|
||||
cmp r6, r7, lsr #27
|
||||
movne r6, r7, lsr #27
|
||||
movne r4, #328*8
|
||||
mlane r5, r4, r6, r12 @ r5=pd = scrpos + prevy*328*8
|
||||
|
||||
bic r1, r1, #0xf800
|
||||
add r1, r5, r1 @ r1=pdest (halfwords)
|
||||
|
||||
mov r7, r7, lsl #16
|
||||
mov r7, r7, lsr #16
|
||||
|
||||
cmp r7, r9, lsr #8
|
||||
bne .dtfcf_notsamecode
|
||||
@ we know stuff about this tile already
|
||||
tst r9, #1
|
||||
bne .dtfcf_loop @ empty tile
|
||||
tst r9, #2
|
||||
bne .dtfcf_singlecolor @ singlecolor tile
|
||||
b .dtfcf_samecode
|
||||
|
||||
.dtfcf_notsamecode:
|
||||
and r4, r9, #0x600000
|
||||
mov r9, r7, lsl #8 @ remember new code
|
||||
|
||||
@ update cram val
|
||||
and r7, r7, #0x6000
|
||||
mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9);
|
||||
|
||||
|
||||
.dtfcf_samecode:
|
||||
|
||||
tst r9, #0x100000 @ vflip?
|
||||
bne .dtfcf_vflip
|
||||
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .dtfcf_hflip
|
||||
|
||||
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
|
||||
Tile 0, 0
|
||||
b .dtfcf_loop
|
||||
|
||||
.dtfcf_hflip:
|
||||
Tile 1, 0
|
||||
b .dtfcf_loop
|
||||
|
||||
.dtfcf_vflip:
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .dtfcf_vflip_hflip
|
||||
|
||||
Tile 0, 1
|
||||
b .dtfcf_loop
|
||||
|
||||
.dtfcf_vflip_hflip:
|
||||
Tile 1, 1
|
||||
b .dtfcf_loop
|
||||
|
||||
.dtfcf_singlecolor:
|
||||
TileSinglecol
|
||||
b .dtfcf_loop
|
||||
|
||||
.pool
|
||||
|
||||
|
||||
@ @@@@@@@@@@@@@@@
|
||||
|
||||
@ (tile_start<<16)|row_start
|
||||
.global DrawWindowFull @ int tstart, int tend, int prio
|
||||
|
||||
DrawWindowFull:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
|
||||
ldr r11, =(Pico+0x22228) @ Pico.video
|
||||
ldrb r12, [r11, #3] @ pvid->reg[3]
|
||||
mov r12, r12, lsl #10
|
||||
|
||||
ldr r4, [r11, #12]
|
||||
mov r5, #1 @ nametab_step
|
||||
tst r4, #1 @ 40 cell mode?
|
||||
andne r12, r12, #0xf000 @ 0x3c<<10
|
||||
andeq r12, r12, #0xf800
|
||||
movne r5, r5, lsl #7
|
||||
moveq r5, r5, lsl #6 @ nametab_step
|
||||
|
||||
and r4, r0, #0xff
|
||||
mla r12, r5, r4, r12 @ nametab += nametab_step*start;
|
||||
|
||||
mov r4, r0, lsr #16 @ r4=start_cell_h
|
||||
add r7, r12, r4, lsl #1
|
||||
|
||||
@ fetch the first code now
|
||||
ldr r10, =(Pico+0x10000) @ lr=Pico.vram
|
||||
ldrh r7, [r10, r7]
|
||||
cmp r2, r7, lsr #15
|
||||
ldmnefd sp!, {r4-r11,pc} @ hack: simply assume that whole window uses same priority
|
||||
|
||||
rsb r8, r4, r1, lsr #16 @ cells (h)
|
||||
orr r8, r8, r4, lsl #8
|
||||
mov r4, r1, lsl #24
|
||||
sub r4, r4, r0, lsl #24
|
||||
orr r8, r8, r4, lsr #8 @ r8=cells_h|(start_cell_h<<8)|(cells_v<<16)
|
||||
sub r8, r8, #0x010000 @ adjust for algo
|
||||
|
||||
mov r9, #0xff000000 @ r9=prevcode=-1
|
||||
|
||||
ldr r11, =framebuff @ r11=scrpos
|
||||
ldr r11, [r11]
|
||||
add r11, r11, #328*8
|
||||
add r11, r11, #8
|
||||
|
||||
and r4, r0, #0xff
|
||||
sub r4, r4, #START_ROW
|
||||
mov r7, #328*8
|
||||
mla r11, r7, r4, r11 @ scrpos+=8*328*(start-START_ROW);
|
||||
mov r0, #0xf
|
||||
|
||||
.dwfloop_outer:
|
||||
and r6, r8, #0xff00 @ r6=tilex
|
||||
add r1, r11, r6, lsr #5 @ r1=pdest
|
||||
add r6, r12, r6, lsr #7
|
||||
add r6, r10, r6 @ r6=Pico.vram+nametab+tilex
|
||||
orr r8, r8, r8, lsl #24
|
||||
sub r8, r8, #0x01000000 @ cell loop counter
|
||||
b .dwfloop_enter
|
||||
|
||||
@ r4 & r7 are scratch in this loop
|
||||
.dwfloop:
|
||||
add r1, r1, #8
|
||||
subs r8, r8, #0x01000000
|
||||
bmi .dwfloop_exit
|
||||
|
||||
.dwfloop_enter:
|
||||
ldrh r7, [r6], #2 @ r7=code
|
||||
|
||||
cmp r7, r9, lsr #8
|
||||
bne .dwf_notsamecode
|
||||
@ we know stuff about this tile already
|
||||
tst r9, #1
|
||||
bne .dwfloop @ empty tile
|
||||
tst r9, #2
|
||||
bne .dwf_singlecolor @ singlecolor tile
|
||||
b .dwf_samecode
|
||||
|
||||
.dwf_notsamecode:
|
||||
and r4, r9, #0x600000
|
||||
mov r9, r7, lsl #8 @ remember new code
|
||||
|
||||
@ update cram val
|
||||
and r7, r7, #0x6000
|
||||
mov r3, r7, asr #9 @ r3=pal=((code&0x6000)>>9);
|
||||
|
||||
.dwf_samecode:
|
||||
|
||||
tst r9, #0x100000 @ vflip?
|
||||
bne .dwf_vflip
|
||||
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .dwf_hflip
|
||||
|
||||
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
|
||||
Tile 0, 0
|
||||
b .dwfloop
|
||||
|
||||
.dwf_hflip:
|
||||
Tile 1, 0
|
||||
b .dwfloop
|
||||
|
||||
.dwf_vflip:
|
||||
tst r9, #0x080000 @ hflip?
|
||||
bne .dwf_vflip_hflip
|
||||
|
||||
Tile 0, 1
|
||||
b .dwfloop
|
||||
|
||||
.dwf_vflip_hflip:
|
||||
Tile 1, 1
|
||||
b .dwfloop
|
||||
|
||||
.dwf_singlecolor:
|
||||
TileSinglecol 1
|
||||
b .dwfloop
|
||||
|
||||
.dwfloop_exit:
|
||||
bic r8, r8, #0xff000000 @ fix r8
|
||||
subs r8, r8, #0x010000
|
||||
ldmmifd sp!, {r4-r11,pc}
|
||||
add r11, r11, #328*8
|
||||
add r12, r12, r5 @ nametab+=nametab_step
|
||||
b .dwfloop_outer
|
||||
|
||||
.pool
|
||||
|
||||
|
||||
@ ---------------- sprites ---------------
|
||||
|
||||
.macro SpriteLoop hflip vflip
|
||||
.if \vflip
|
||||
mov r1, r5, lsr #24 @ height
|
||||
mov r0, #328*8
|
||||
mla r11, r1, r0, r11 @ scrpos+=height*328*8;
|
||||
add r12, r12, r1, lsl #3 @ sy+=height*8
|
||||
.endif
|
||||
mov r0, #0xf
|
||||
.if \hflip
|
||||
and r1, r5, #0xff
|
||||
add r8, r8, r1, lsl #3 @ sx+=width*8
|
||||
58:
|
||||
cmp r8, #336
|
||||
blt 51f
|
||||
add r9, r9, r5, lsr #16
|
||||
sub r5, r5, #1 @ sub width
|
||||
sub r8, r8, #8
|
||||
b 58b
|
||||
.else
|
||||
cmp r8, #0 @ skip tiles hidden on the left of screen
|
||||
bgt 51f
|
||||
58:
|
||||
add r9, r9, r5, lsr #16
|
||||
sub r5, r5, #1
|
||||
adds r8, r8, #8
|
||||
ble 58b
|
||||
b 51f
|
||||
.endif
|
||||
|
||||
50: @ outer
|
||||
.if !\hflip
|
||||
add r8, r8, #8 @ sx+=8
|
||||
.endif
|
||||
bic r5, r5, #0xff000000 @ fix height
|
||||
orr r5, r5, r5, lsl #16
|
||||
|
||||
51: @ outer_enter
|
||||
sub r5, r5, #1 @ width--
|
||||
movs r1, r5, lsl #24
|
||||
ldmmifd sp!, {r4-r11,pc} @ end of tile
|
||||
.if \hflip
|
||||
subs r8, r8, #8 @ sx-=8
|
||||
ldmlefd sp!, {r4-r11,pc} @ tile offscreen
|
||||
.else
|
||||
cmp r8, #328
|
||||
ldmgefd sp!, {r4-r11,pc} @ tile offscreen
|
||||
.endif
|
||||
mov r6, r12 @ r6=sy
|
||||
add r1, r11, r8 @ pdest=scrpos+sx
|
||||
b 53f
|
||||
|
||||
52: @ inner
|
||||
add r9, r9, #1<<8 @ tile++
|
||||
.if !\vflip
|
||||
add r6, r6, #8 @ sy+=8
|
||||
add r1, r1, #328*8
|
||||
.endif
|
||||
|
||||
53: @ inner_enter
|
||||
@ end of sprite?
|
||||
subs r5, r5, #0x01000000
|
||||
bmi 50b @ ->outer
|
||||
.if \vflip
|
||||
sub r6, r6, #8 @ sy-=8
|
||||
sub r1, r1, #328*8
|
||||
.endif
|
||||
|
||||
@ offscreen?
|
||||
cmp r6, #(START_ROW*8)
|
||||
ble 52b
|
||||
|
||||
cmp r6, #(END_ROW*8+8)
|
||||
bge 52b
|
||||
|
||||
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
|
||||
Tile \hflip, \vflip
|
||||
b 52b
|
||||
.endm
|
||||
|
||||
|
||||
.global DrawSpriteFull @ unsigned int *sprite
|
||||
|
||||
DrawSpriteFull:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
|
||||
ldr r3, [r0] @ sprite[0]
|
||||
mov r5, r3, lsl #4
|
||||
mov r6, r5, lsr #30
|
||||
add r6, r6, #1 @ r6=width
|
||||
mov r5, r5, lsl #2
|
||||
mov r5, r5, lsr #30
|
||||
add r5, r5, #1 @ r5=height
|
||||
|
||||
mov r12, r3, lsl #23
|
||||
mov r12, r12, lsr #23
|
||||
sub r12, r12, #0x78 @ r12=sy
|
||||
|
||||
ldr lr, [r0, #4] @ lr=code
|
||||
mov r8, lr, lsl #7
|
||||
mov r8, r8, lsr #23
|
||||
sub r8, r8, #0x78 @ r8=sx
|
||||
|
||||
mov r9, lr, lsl #21
|
||||
mov r9, r9, lsr #13 @ r9=tile<<8
|
||||
|
||||
and r3, lr, #0x6000
|
||||
mov r3, r3, lsr #9 @ r3=pal=((code>>9)&0x30);
|
||||
|
||||
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
|
||||
|
||||
ldr r11, =framebuff @ r11=scrpos
|
||||
ldr r11, [r11]
|
||||
sub r1, r12, #(START_ROW*8)
|
||||
mov r0, #328
|
||||
mla r11, r1, r0, r11 @ scrpos+=(sy-START_ROW*8)*328;
|
||||
|
||||
orr r5, r5, r5, lsl #16 @
|
||||
orr r5, r6, r5, lsl #8 @ r5=width|(height<<8)|(height<<24)
|
||||
|
||||
tst lr, #0x1000 @ vflip?
|
||||
bne .dsf_vflip
|
||||
|
||||
tst lr, #0x0800 @ hflip?
|
||||
bne .dsf_hflip
|
||||
|
||||
SpriteLoop 0, 0
|
||||
|
||||
.dsf_hflip:
|
||||
SpriteLoop 1, 0
|
||||
|
||||
.dsf_vflip:
|
||||
tst lr, #0x0800 @ hflip?
|
||||
bne .dsf_vflip_hflip
|
||||
|
||||
SpriteLoop 0, 1
|
||||
|
||||
.dsf_vflip_hflip:
|
||||
SpriteLoop 1, 1
|
||||
|
||||
.pool
|
||||
|
||||
|
1423
Pico/Draw_.s
Normal file
1423
Pico/Draw_.s
Normal file
File diff suppressed because it is too large
Load diff
1301
Pico/Draw_sh.c
Normal file
1301
Pico/Draw_sh.c
Normal file
File diff suppressed because it is too large
Load diff
1527
Pico/Draw_sh.s
Normal file
1527
Pico/Draw_sh.s
Normal file
File diff suppressed because it is too large
Load diff
829
Pico/Memory.c
Normal file
829
Pico/Memory.c
Normal file
|
@ -0,0 +1,829 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
//#define __debug_io
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
#include "sound/sound.h"
|
||||
#include "sound/ym2612.h"
|
||||
#include "sound/sn76496.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
extern unsigned int lastSSRamWrite; // used by serial SRAM code
|
||||
|
||||
#ifdef _ASM_MEMORY_C
|
||||
u8 PicoRead8(u32 a);
|
||||
u16 PicoRead16(u32 a);
|
||||
void PicoWriteRomHW_SSF2(u32 a,u32 d);
|
||||
void PicoWriteRomHW_in1 (u32 a,u32 d);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
// cyclone debug mode
|
||||
u32 lastread_a, lastread_d[16]={0,}, lastwrite_cyc_d[16]={0,}, lastwrite_mus_d[16]={0,};
|
||||
int lrp_cyc=0, lrp_mus=0, lwp_cyc=0, lwp_mus=0;
|
||||
extern unsigned int ppop;
|
||||
#endif
|
||||
|
||||
#if defined(EMU_C68K) || defined(EMU_A68K)
|
||||
static __inline int PicoMemBase(u32 pc)
|
||||
{
|
||||
int membase=0;
|
||||
|
||||
if (pc<Pico.romsize+4)
|
||||
{
|
||||
membase=(int)Pico.rom; // Program Counter in Rom
|
||||
}
|
||||
else if ((pc&0xe00000)==0xe00000)
|
||||
{
|
||||
membase=(int)Pico.ram-(pc&0xff0000); // Program Counter in Ram
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error - Program Counter is invalid
|
||||
membase=(int)Pico.rom;
|
||||
}
|
||||
|
||||
return membase;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EMU_A68K
|
||||
extern u8 *OP_ROM=NULL,*OP_RAM=NULL;
|
||||
#endif
|
||||
|
||||
static u32 CPU_CALL PicoCheckPc(u32 pc)
|
||||
{
|
||||
u32 ret=0;
|
||||
#if defined(EMU_C68K)
|
||||
pc-=PicoCpu.membase; // Get real pc
|
||||
pc&=0xfffffe;
|
||||
|
||||
PicoCpu.membase=PicoMemBase(pc);
|
||||
|
||||
ret = PicoCpu.membase+pc;
|
||||
#elif defined(EMU_A68K)
|
||||
OP_ROM=(u8 *)PicoMemBase(pc);
|
||||
|
||||
// don't bother calling us back unless it's outside the 64k segment
|
||||
M68000_regs.AsmBank=(pc>>16);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int PicoInitPc(u32 pc)
|
||||
{
|
||||
PicoCheckPc(pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef _ASM_MEMORY_C
|
||||
void PicoMemReset()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
#ifndef _ASM_MEMORY_C
|
||||
// address must already be checked
|
||||
static int SRAMRead(u32 a)
|
||||
{
|
||||
u8 *d = SRam.data-SRam.start+a;
|
||||
return (d[0]<<8)|d[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
static int PadRead(int i)
|
||||
{
|
||||
int pad=0,value=0,TH;
|
||||
pad=~PicoPad[i]; // Get inverse of pad MXYZ SACB RLDU
|
||||
TH=Pico.ioports[i+1]&0x40;
|
||||
|
||||
if(PicoOpt & 0x20) { // 6 button gamepad enabled
|
||||
int phase = Pico.m.padTHPhase[i];
|
||||
|
||||
if(phase == 2 && !TH) {
|
||||
value=(pad&0xc0)>>2; // ?0SA 0000
|
||||
goto end;
|
||||
} else if(phase == 3 && TH) {
|
||||
value=(pad&0x30)|((pad>>8)&0xf); // ?1CB MXYZ
|
||||
goto end;
|
||||
} else if(phase == 3 && !TH) {
|
||||
value=((pad&0xc0)>>2)|0x0f; // ?0SA 1111
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if(TH) value=(pad&0x3f); // ?1CB RLDU
|
||||
else value=((pad&0xc0)>>2)|(pad&3); // ?0SA 00DU
|
||||
|
||||
end:
|
||||
|
||||
// orr the bits, which are set as output
|
||||
value |= Pico.ioports[i+1]&Pico.ioports[i+4];
|
||||
|
||||
return value; // will mirror later
|
||||
}
|
||||
|
||||
u8 z80Read8(u32 a)
|
||||
{
|
||||
if(Pico.m.z80Run&1) return 0;
|
||||
|
||||
a&=0x1fff;
|
||||
|
||||
if(!(PicoOpt&4)) {
|
||||
// Z80 disabled, do some faking
|
||||
static u8 zerosent = 0;
|
||||
if(a == Pico.m.z80_lastaddr) { // probably polling something
|
||||
u8 d = Pico.m.z80_fakeval;
|
||||
if((d & 0xf) == 0xf && !zerosent) {
|
||||
d = 0; zerosent = 1;
|
||||
} else {
|
||||
Pico.m.z80_fakeval++;
|
||||
zerosent = 0;
|
||||
}
|
||||
return d;
|
||||
} else {
|
||||
Pico.m.z80_fakeval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Pico.m.z80_lastaddr = (u16) a;
|
||||
return Pico.zram[a];
|
||||
}
|
||||
|
||||
|
||||
// for nonstandard reads
|
||||
#ifndef _ASM_MEMORY_C
|
||||
static
|
||||
#endif
|
||||
u32 UnusualRead16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
dprintf("strange r%i: %06x @%06x", realsize, a&0xffffff, SekPc);
|
||||
|
||||
// for games with simple protection devices, discovered by Haze
|
||||
// some dumb detection is used, but that should be enough to make things work
|
||||
if ((a>>22) == 1 && Pico.romsize >= 512*1024) {
|
||||
if (*(int *)(Pico.rom+0x123e4) == 0x00550c39 && *(int *)(Pico.rom+0x123e8) == 0x00000040) { // Super Bubble Bobble (Unl) [!]
|
||||
if (a == 0x400000) { d=0x55<<8; goto end; }
|
||||
else if (a == 0x400002) { d=0x0f<<8; goto end; }
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0x008c4) == 0x66240055 && *(int *)(Pico.rom+0x008c8) == 0x00404df9) { // Smart Mouse (Unl)
|
||||
if (a == 0x400000) { d=0x55<<8; goto end; }
|
||||
else if (a == 0x400002) { d=0x0f<<8; goto end; }
|
||||
else if (a == 0x400004) { d=0xaa<<8; goto end; }
|
||||
else if (a == 0x400006) { d=0xf0<<8; goto end; }
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0x00404) == 0x00a90600 && *(int *)(Pico.rom+0x00408) == 0x6708b013) { // King of Fighters '98, The (Unl) [!]
|
||||
if (a == 0x480000 || a == 0x4800e0 || a == 0x4824a0 || a == 0x488880) { d=0xaa<<8; goto end; }
|
||||
else if (a == 0x4a8820) { d=0x0a<<8; goto end; }
|
||||
// there is also a read @ 0x4F8820 which needs 0, but that is returned in default case
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0x01b24) == 0x004013f9 && *(int *)(Pico.rom+0x01b28) == 0x00ff0000) { // Mahjong Lover (Unl) [!]
|
||||
if (a == 0x400000) { d=0x90<<8; goto end; }
|
||||
else if (a == 0x401000) { d=0xd3<<8; goto end; } // this one doesn't seem to be needed, the code does 2 comparisons and only then
|
||||
// checks the result, which is of the above one. Left it just in case.
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0x05254) == 0x0c3962d0 && *(int *)(Pico.rom+0x05258) == 0x00400055) { // Elf Wor (Unl)
|
||||
if (a == 0x400000) { d=0x55<<8; goto end; }
|
||||
else if (a == 0x400004) { d=0xc9<<8; goto end; } // this check is done if the above one fails
|
||||
else if (a == 0x400002) { d=0x0f<<8; goto end; }
|
||||
else if (a == 0x400006) { d=0x18<<8; goto end; } // similar to above
|
||||
}
|
||||
// our default behaviour is to return whatever was last written a 0x400000-0x7fffff range (used by Squirrel King (R) [!])
|
||||
// Lion King II, The (Unl) [!] writes @ 400000 and wants to get that val @ 400002 and wites another val
|
||||
// @ 400004 which is expected @ 400006, so we really remember 2 values here
|
||||
d = Pico.m.prot_bytes[(a>>2)&1]<<8;
|
||||
}
|
||||
else if (a == 0xa13000 && Pico.romsize >= 1024*1024) {
|
||||
if (*(int *)(Pico.rom+0xc8af0) == 0x30133013 && *(int *)(Pico.rom+0xc8af4) == 0x000f0240) { // Rockman X3 (Unl) [!]
|
||||
d=0x0c; goto end;
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0x28888) == 0x07fc0000 && *(int *)(Pico.rom+0x2888c) == 0x4eb94e75) { // Bug's Life, A (Unl) [!]
|
||||
d=0x28; goto end; // does the check from RAM
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0xc8778) == 0x30133013 && *(int *)(Pico.rom+0xc877c) == 0x000f0240) { // Super Mario Bros. (Unl) [!]
|
||||
d=0x0c; goto end; // seems to be the same code as in Rockman X3 (Unl) [!]
|
||||
}
|
||||
else if (*(int *)(Pico.rom+0xf20ec) == 0x30143013 && *(int *)(Pico.rom+0xf20f0) == 0x000f0200) { // Super Mario 2 1998 (Unl) [!]
|
||||
d=0x0a; goto end;
|
||||
}
|
||||
}
|
||||
else if (a == 0xa13002) { // Pocket Monsters (Unl)
|
||||
d=0x01; goto end;
|
||||
}
|
||||
else if (a == 0xa1303E) { // Pocket Monsters (Unl)
|
||||
d=0x1f; goto end;
|
||||
}
|
||||
else if (a == 0x30fe02) {
|
||||
// Virtua Racing - just for fun
|
||||
// this seems to be some flag that SVP is ready or something similar
|
||||
d=1; goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
dprintf("ret = %04x", d);
|
||||
return d;
|
||||
}
|
||||
|
||||
#ifndef _ASM_MEMORY_C
|
||||
static
|
||||
#endif
|
||||
u32 OtherRead16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xff0000)==0xa00000) {
|
||||
if ((a&0x4000)==0x0000) { d=z80Read8(a); d|=d<<8; goto end; } // Z80 ram (not byteswaped)
|
||||
if ((a&0x6000)==0x4000) { if(PicoOpt&1) d=YM2612Read(); else d=Pico.m.rotate++&3; goto end; } // 0x4000-0x5fff, Fudge if disabled
|
||||
d=0xffff; goto end;
|
||||
}
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
switch(a) {
|
||||
case 0: d=Pico.m.hardware; break; // Hardware value (Version register)
|
||||
case 1: d=PadRead(0); d|=Pico.ioports[1]&0x80; break;
|
||||
case 2: d=PadRead(1); d|=Pico.ioports[2]&0x80; break;
|
||||
default: d=Pico.ioports[a]; break; // IO ports can be used as RAM
|
||||
}
|
||||
d|=d<<8;
|
||||
goto end;
|
||||
}
|
||||
// |=0x80 for Shadow of the Beast & Super Offroad; rotate fakes next fetched instruction for Time Killers
|
||||
if (a==0xa11100) { d=((Pico.m.z80Run&1)<<8)|0x8000|Pico.m.rotate++; goto end; }
|
||||
|
||||
#ifndef _ASM_MEMORY_C
|
||||
if ((a&0xe700e0)==0xc00000) { d=PicoVideoRead(a); goto end; }
|
||||
#endif
|
||||
|
||||
d = UnusualRead16(a, realsize);
|
||||
|
||||
end:
|
||||
return d;
|
||||
}
|
||||
|
||||
//extern UINT32 mz80GetRegisterValue(void *, UINT32);
|
||||
|
||||
static void OtherWrite8(u32 a,u32 d,int realsize)
|
||||
{
|
||||
if ((a&0xe700f9)==0xc00011||(a&0xff7ff9)==0xa07f11) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound
|
||||
if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d; return; } // Z80 ram
|
||||
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d); return; } // FM Sound
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
// 6 button gamepad: if TH went from 0 to 1, gamepad changes state
|
||||
if(PicoOpt&0x20) {
|
||||
if(a==1) {
|
||||
Pico.m.padDelay[0] = 0;
|
||||
if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++;
|
||||
}
|
||||
else if(a==2) {
|
||||
Pico.m.padDelay[1] = 0;
|
||||
if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++;
|
||||
}
|
||||
}
|
||||
Pico.ioports[a]=(u8)d; // IO ports can be used as RAM
|
||||
return;
|
||||
}
|
||||
if (a==0xa11100) {
|
||||
extern int z80startCycle, z80stopCycle;
|
||||
//int lineCycles=(488-SekCyclesLeft)&0x1ff;
|
||||
d&=1; d^=1;
|
||||
if(!d) {
|
||||
// hack: detect a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III)
|
||||
if((PicoOpt&4) && Pico.m.z80Run==1) z80_run(20);
|
||||
z80stopCycle = SekCyclesDone();
|
||||
//z80ExtraCycles += (lineCycles>>1)-(lineCycles>>5); // only meaningful in PicoFrameHints()
|
||||
} else {
|
||||
z80startCycle = SekCyclesDone();
|
||||
//if(Pico.m.scanline != -1)
|
||||
//z80ExtraCycles -= (lineCycles>>1)-(lineCycles>>5)+16;
|
||||
}
|
||||
//dprintf("set_zrun: %i [%i|%i] zPC=%04x @%06x", d, Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0), SekPc);
|
||||
Pico.m.z80Run=(u8)d; return;
|
||||
}
|
||||
if (a==0xa11200) { if(!(d&1)) z80_reset(); return; }
|
||||
|
||||
if ((a&0xff7f00)==0xa06000) // Z80 BANK register
|
||||
{
|
||||
Pico.m.z80_bank68k>>=1;
|
||||
Pico.m.z80_bank68k|=(d&1)<<8;
|
||||
Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)(d|(d<<8))); return; } // Byte access gets mirrored
|
||||
|
||||
// sram
|
||||
//if(a==0x200000) dprintf("cc : %02x @ %06x [%i|%i]", d, SekPc, SekCyclesDoneT(), SekCyclesDone());
|
||||
//if(a==0x200001) dprintf("w8 : %02x @ %06x [%i]", d, SekPc, SekCyclesDoneT());
|
||||
if(a >= SRam.start && a <= SRam.end) {
|
||||
unsigned int sreg = Pico.m.sram_reg;
|
||||
if(!(sreg & 0x10)) {
|
||||
// not detected SRAM
|
||||
if((a&~1)==0x200000) {
|
||||
Pico.m.sram_reg|=4; // this should be a game with EEPROM (like NBA Jam)
|
||||
SRam.start=0x200000; SRam.end=SRam.start+1;
|
||||
}
|
||||
Pico.m.sram_reg|=0x10;
|
||||
}
|
||||
if(sreg & 4) { // EEPROM write
|
||||
if(SekCyclesDoneT()-lastSSRamWrite < 46) {
|
||||
// just update pending state
|
||||
SRAMUpdPending(a, d);
|
||||
} else {
|
||||
SRAMWriteEEPROM(sreg>>6); // execute pending
|
||||
SRAMUpdPending(a, d);
|
||||
lastSSRamWrite = SekCyclesDoneT();
|
||||
}
|
||||
} else if(!(sreg & 2)) {
|
||||
u8 *pm=(u8 *)(SRam.data-SRam.start+a);
|
||||
if(*pm != (u8)d) {
|
||||
SRam.changed = 1;
|
||||
*pm=(u8)d;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _ASM_MEMORY_C
|
||||
// special ROM hardware (currently only banking and sram reg supported)
|
||||
if((a&0xfffff1) == 0xA130F1) {
|
||||
PicoWriteRomHW_SSF2(a, d); // SSF2 or SRAM
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// sram access register
|
||||
if(a == 0xA130F1) {
|
||||
Pico.m.sram_reg = (u8)(d&3);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
dprintf("strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc);
|
||||
|
||||
if(a >= 0xA13004 && a < 0xA13040) {
|
||||
// dumb 12-in-1 or 4-in-1 banking support
|
||||
int len;
|
||||
a &= 0x3f; a <<= 16;
|
||||
len = Pico.romsize - a;
|
||||
if (len <= 0) return; // invalid/missing bank
|
||||
if (len > 0x200000) len = 0x200000; // 2 megs
|
||||
memcpy(Pico.rom, Pico.rom+a, len); // code which does this is in RAM so this is safe.
|
||||
return;
|
||||
}
|
||||
|
||||
// for games with simple protection devices, discovered by Haze
|
||||
else if ((a>>22) == 1)
|
||||
Pico.m.prot_bytes[(a>>2)&1] = (u8)d;
|
||||
}
|
||||
|
||||
static void OtherWrite16(u32 a,u32 d)
|
||||
{
|
||||
if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; }
|
||||
if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8); return; } // Z80 ram (MSB only)
|
||||
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
// 6 button gamepad: if TH went from 0 to 1, gamepad changes state
|
||||
if(PicoOpt&0x20) {
|
||||
if(a==1) {
|
||||
Pico.m.padDelay[0] = 0;
|
||||
if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++;
|
||||
}
|
||||
else if(a==2) {
|
||||
Pico.m.padDelay[1] = 0;
|
||||
if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++;
|
||||
}
|
||||
}
|
||||
Pico.ioports[a]=(u8)d; // IO ports can be used as RAM
|
||||
return;
|
||||
}
|
||||
if (a==0xa11100) { OtherWrite8(a, d>>8, 16); return; }
|
||||
if (a==0xa11200) { if(!(d&0x100)) z80_reset(); return; }
|
||||
|
||||
OtherWrite8(a, d>>8, 16);
|
||||
OtherWrite8(a+1,d&0xff, 16);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Read Rom and read Ram
|
||||
|
||||
#ifndef _ASM_MEMORY_C
|
||||
u8 CPU_CALL PicoRead8(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { d = *(u8 *)(Pico.ram+((a^1)&0xffff)); goto end; } // Ram
|
||||
|
||||
a&=0xffffff;
|
||||
|
||||
#if !(defined(EMU_C68K) && defined(EMU_M68K))
|
||||
// sram
|
||||
if(a >= SRam.start && a <= SRam.end) {
|
||||
unsigned int sreg = Pico.m.sram_reg;
|
||||
if(!(sreg & 0x10) && (sreg & 1) && a > 0x200001) { // not yet detected SRAM
|
||||
Pico.m.sram_reg|=0x10; // should be normal SRAM
|
||||
}
|
||||
if(sreg & 4) { // EEPROM read
|
||||
d = SRAMReadEEPROM();
|
||||
goto end;
|
||||
} else if(sreg & 1) {
|
||||
d = *(u8 *)(SRam.data-SRam.start+a);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (a<Pico.romsize) { d = *(u8 *)(Pico.rom+(a^1)); goto end; } // Rom
|
||||
if ((a&0xff4000)==0xa00000) { d=z80Read8(a); goto end; } // Z80 Ram
|
||||
|
||||
d=OtherRead16(a&~1, 8); if ((a&1)==0) d>>=8;
|
||||
|
||||
end:
|
||||
|
||||
//if ((a&0xe0ffff)==0xe0AE57+0x69c)
|
||||
// dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc);
|
||||
//if ((a&0xe0ffff)==0xe0a9ba+0x69c)
|
||||
// dprintf("r8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
//if(a==0x200001) dprintf("r8 : %02x @ %06x [%i]", d, SekPc, SekCyclesDoneT());
|
||||
//dprintf("r8 : %06x, %02x @%06x [%03i]", a&0xffffff, (u8)d, SekPc, Pico.m.scanline);
|
||||
#ifdef __debug_io
|
||||
dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
if(a>=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) {
|
||||
lastread_a = a;
|
||||
lastread_d[lrp_cyc++&15] = (u8)d;
|
||||
}
|
||||
#endif
|
||||
return (u8)d;
|
||||
}
|
||||
|
||||
u16 CPU_CALL PicoRead16(u32 a)
|
||||
{
|
||||
u16 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { d=*(u16 *)(Pico.ram+(a&0xfffe)); goto end; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
#if !(defined(EMU_C68K) && defined(EMU_M68K))
|
||||
// sram
|
||||
if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg & 1)) {
|
||||
d = (u16) SRAMRead(a);
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (a<Pico.romsize) { d = *(u16 *)(Pico.rom+a); goto end; } // Rom
|
||||
|
||||
d = (u16)OtherRead16(a, 16);
|
||||
|
||||
end:
|
||||
//if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c)
|
||||
// dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
#ifdef __debug_io
|
||||
dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
if(a>=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) {
|
||||
lastread_a = a;
|
||||
lastread_d[lrp_cyc++&15] = d;
|
||||
}
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
u32 CPU_CALL PicoRead32(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); d = (pm[0]<<16)|pm[1]; goto end; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// sram
|
||||
if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg & 1)) {
|
||||
d = (SRAMRead(a)<<16)|SRAMRead(a+2);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (a<Pico.romsize) { u16 *pm=(u16 *)(Pico.rom+a); d = (pm[0]<<16)|pm[1]; goto end; } // Rom
|
||||
|
||||
d = (OtherRead16(a, 32)<<16)|OtherRead16(a+2, 32);
|
||||
|
||||
end:
|
||||
#ifdef __debug_io
|
||||
dprintf("r32: %06x, %08x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
if(a>=Pico.romsize&&(ppop&0x3f)!=0x3a&&(ppop&0x3f)!=0x3b) {
|
||||
lastread_a = a;
|
||||
lastread_d[lrp_cyc++&15] = d;
|
||||
}
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Write Ram
|
||||
|
||||
static void CPU_CALL PicoWrite8(u32 a,u8 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
lastwrite_cyc_d[lwp_cyc++&15] = d;
|
||||
#endif
|
||||
//if ((a&0xe0ffff)==0xe0a9ba+0x69c)
|
||||
// dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { u8 *pm=(u8 *)(Pico.ram+((a^1)&0xffff)); pm[0]=d; return; } // Ram
|
||||
|
||||
a&=0xffffff;
|
||||
OtherWrite8(a,d,8);
|
||||
}
|
||||
|
||||
static void CPU_CALL PicoWrite16(u32 a,u16 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w16: %06x, %04x", a&0xffffff, d);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
lastwrite_cyc_d[lwp_cyc++&15] = d;
|
||||
#endif
|
||||
//if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c)
|
||||
// dprintf("w16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
OtherWrite16(a,d);
|
||||
}
|
||||
|
||||
static void CPU_CALL PicoWrite32(u32 a,u32 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w32: %06x, %08x", a&0xffffff, d);
|
||||
#endif
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
lastwrite_cyc_d[lwp_cyc++&15] = d;
|
||||
#endif
|
||||
|
||||
if ((a&0xe00000)==0xe00000)
|
||||
{
|
||||
// Ram:
|
||||
u16 *pm=(u16 *)(Pico.ram+(a&0xfffe));
|
||||
pm[0]=(u16)(d>>16); pm[1]=(u16)d;
|
||||
return;
|
||||
}
|
||||
|
||||
a&=0xfffffe;
|
||||
OtherWrite16(a, (u16)(d>>16));
|
||||
OtherWrite16(a+2,(u16)d);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
int PicoMemInit()
|
||||
{
|
||||
#ifdef EMU_C68K
|
||||
// Setup memory callbacks:
|
||||
PicoCpu.checkpc=PicoCheckPc;
|
||||
PicoCpu.fetch8 =PicoCpu.read8 =PicoRead8;
|
||||
PicoCpu.fetch16=PicoCpu.read16=PicoRead16;
|
||||
PicoCpu.fetch32=PicoCpu.read32=PicoRead32;
|
||||
PicoCpu.write8 =PicoWrite8;
|
||||
PicoCpu.write16=PicoWrite16;
|
||||
PicoCpu.write32=PicoWrite32;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef EMU_A68K
|
||||
struct A68KInter
|
||||
{
|
||||
u32 unknown;
|
||||
u8 (__fastcall *Read8) (u32 a);
|
||||
u16 (__fastcall *Read16)(u32 a);
|
||||
u32 (__fastcall *Read32)(u32 a);
|
||||
void (__fastcall *Write8) (u32 a,u8 d);
|
||||
void (__fastcall *Write16) (u32 a,u16 d);
|
||||
void (__fastcall *Write32) (u32 a,u32 d);
|
||||
void (__fastcall *ChangePc)(u32 a);
|
||||
u8 (__fastcall *PcRel8) (u32 a);
|
||||
u16 (__fastcall *PcRel16)(u32 a);
|
||||
u32 (__fastcall *PcRel32)(u32 a);
|
||||
u16 (__fastcall *Dir16)(u32 a);
|
||||
u32 (__fastcall *Dir32)(u32 a);
|
||||
};
|
||||
|
||||
struct A68KInter a68k_memory_intf=
|
||||
{
|
||||
0,
|
||||
PicoRead8,
|
||||
PicoRead16,
|
||||
PicoRead32,
|
||||
PicoWrite8,
|
||||
PicoWrite16,
|
||||
PicoWrite32,
|
||||
PicoCheckPc,
|
||||
PicoRead8,
|
||||
PicoRead16,
|
||||
PicoRead32,
|
||||
PicoRead16, // unused
|
||||
PicoRead32, // unused
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
unsigned int m68k_read_pcrelative_CD8 (unsigned int a);
|
||||
unsigned int m68k_read_pcrelative_CD16(unsigned int a);
|
||||
unsigned int m68k_read_pcrelative_CD32(unsigned int a);
|
||||
|
||||
// these are allowed to access RAM
|
||||
unsigned int m68k_read_pcrelative_8 (unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(PicoMCD&1) return m68k_read_pcrelative_CD8(a);
|
||||
if(a<Pico.romsize) return *(u8 *)(Pico.rom+(a^1)); // Rom
|
||||
if((a&0xe00000)==0xe00000) return *(u8 *)(Pico.ram+((a^1)&0xffff)); // Ram
|
||||
return 0;//(u8) lastread_d;
|
||||
}
|
||||
unsigned int m68k_read_pcrelative_16(unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(PicoMCD&1) return m68k_read_pcrelative_CD16(a);
|
||||
if(a<Pico.romsize) return *(u16 *)(Pico.rom+(a&~1)); // Rom
|
||||
if((a&0xe00000)==0xe00000) return *(u16 *)(Pico.ram+(a&0xfffe)); // Ram
|
||||
return 0;//(u16) lastread_d;
|
||||
}
|
||||
unsigned int m68k_read_pcrelative_32(unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(PicoMCD&1) return m68k_read_pcrelative_CD32(a);
|
||||
if(a<Pico.romsize) { u16 *pm=(u16 *)(Pico.rom+(a&~1)); return (pm[0]<<16)|pm[1]; }
|
||||
if((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); return (pm[0]<<16)|pm[1]; } // Ram
|
||||
return 0;//lastread_d;
|
||||
}
|
||||
|
||||
unsigned int m68k_read_immediate_16(unsigned int a) { return m68k_read_pcrelative_16(a); }
|
||||
unsigned int m68k_read_immediate_32(unsigned int a) { return m68k_read_pcrelative_32(a); }
|
||||
unsigned int m68k_read_disassembler_8 (unsigned int a) { return m68k_read_pcrelative_8 (a); }
|
||||
unsigned int m68k_read_disassembler_16(unsigned int a) { return m68k_read_pcrelative_16(a); }
|
||||
unsigned int m68k_read_disassembler_32(unsigned int a) { return m68k_read_pcrelative_32(a); }
|
||||
|
||||
#ifdef EMU_C68K
|
||||
// ROM only
|
||||
unsigned int m68k_read_memory_8(unsigned int a) { if(a<Pico.romsize) return *(u8 *) (Pico.rom+(a^1)); return (u8) lastread_d[lrp_mus++&15]; }
|
||||
unsigned int m68k_read_memory_16(unsigned int a) { if(a<Pico.romsize) return *(u16 *)(Pico.rom+(a&~1));return (u16) lastread_d[lrp_mus++&15]; }
|
||||
unsigned int m68k_read_memory_32(unsigned int a) { if(a<Pico.romsize) {u16 *pm=(u16 *)(Pico.rom+(a&~1));return (pm[0]<<16)|pm[1];} return lastread_d[lrp_mus++&15]; }
|
||||
|
||||
// ignore writes, Cyclone already done that
|
||||
void m68k_write_memory_8(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }
|
||||
void m68k_write_memory_16(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }
|
||||
void m68k_write_memory_32(unsigned int address, unsigned int value) { lastwrite_mus_d[lwp_mus++&15] = value; }
|
||||
#else
|
||||
unsigned char PicoReadCD8w (unsigned int a);
|
||||
unsigned short PicoReadCD16w(unsigned int a);
|
||||
unsigned int PicoReadCD32w(unsigned int a);
|
||||
void PicoWriteCD8w (unsigned int a, unsigned char d);
|
||||
void PicoWriteCD16w(unsigned int a, unsigned short d);
|
||||
void PicoWriteCD32w(unsigned int a, unsigned int d);
|
||||
|
||||
unsigned int m68k_read_memory_8(unsigned int address)
|
||||
{
|
||||
return (PicoMCD&1) ? PicoReadCD8w(address) : PicoRead8(address);
|
||||
}
|
||||
|
||||
unsigned int m68k_read_memory_16(unsigned int address)
|
||||
{
|
||||
return (PicoMCD&1) ? PicoReadCD16w(address) : PicoRead16(address);
|
||||
}
|
||||
|
||||
unsigned int m68k_read_memory_32(unsigned int address)
|
||||
{
|
||||
return (PicoMCD&1) ? PicoReadCD32w(address) : PicoRead32(address);
|
||||
}
|
||||
|
||||
void m68k_write_memory_8(unsigned int address, unsigned int value)
|
||||
{
|
||||
if (PicoMCD&1) PicoWriteCD8w(address, (u8)value); else PicoWrite8(address, (u8)value);
|
||||
}
|
||||
|
||||
void m68k_write_memory_16(unsigned int address, unsigned int value)
|
||||
{
|
||||
if (PicoMCD&1) PicoWriteCD16w(address,(u16)value); else PicoWrite16(address,(u16)value);
|
||||
}
|
||||
|
||||
void m68k_write_memory_32(unsigned int address, unsigned int value)
|
||||
{
|
||||
if (PicoMCD&1) PicoWriteCD32w(address, value); else PicoWrite32(address, value);
|
||||
}
|
||||
#endif
|
||||
#endif // EMU_M68K
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// z80 memhandlers
|
||||
|
||||
unsigned char z80_read(unsigned short a)
|
||||
{
|
||||
u8 ret = 0;
|
||||
|
||||
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
||||
{
|
||||
if(PicoOpt&1) ret = (u8) YM2612Read();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (a>=0x8000)
|
||||
{
|
||||
u32 addr68k;
|
||||
addr68k=Pico.m.z80_bank68k<<15;
|
||||
addr68k+=a&0x7fff;
|
||||
|
||||
ret = (u8) PicoRead8(addr68k);
|
||||
//dprintf("z80->68k w8 : %06x, %02x", addr68k, ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// should not be needed || dprintf("z80_read RAM");
|
||||
if (a<0x4000) { ret = (u8) Pico.zram[a&0x1fff]; goto end; }
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned short z80_read16(unsigned short a)
|
||||
{
|
||||
//dprintf("z80_read16");
|
||||
|
||||
return (u16) ( (u16)z80_read(a) | ((u16)z80_read((u16)(a+1))<<8) );
|
||||
}
|
||||
|
||||
void z80_write(unsigned char data, unsigned short a)
|
||||
{
|
||||
//if (a<0x4000)
|
||||
// dprintf("z80 w8 : %06x, %02x @%04x", a, data, mz80GetRegisterValue(NULL, 0));
|
||||
|
||||
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
||||
{
|
||||
if(PicoOpt&1) emustatus|=YM2612Write(a, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a&0xfff9)==0x7f11) // 7f11 7f13 7f15 7f17
|
||||
{
|
||||
if(PicoOpt&2) SN76496Write(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a>>8)==0x60)
|
||||
{
|
||||
Pico.m.z80_bank68k>>=1;
|
||||
Pico.m.z80_bank68k|=(data&1)<<8;
|
||||
Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one
|
||||
return;
|
||||
}
|
||||
|
||||
if (a>=0x8000)
|
||||
{
|
||||
u32 addr68k;
|
||||
addr68k=Pico.m.z80_bank68k<<15;
|
||||
addr68k+=a&0x7fff;
|
||||
PicoWrite8(addr68k, data);
|
||||
//dprintf("z80->68k w8 : %06x, %02x", addr68k, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// should not be needed, drZ80 knows how to access RAM itself || dprintf("z80_write RAM @ %08x", lr);
|
||||
if (a<0x4000) { Pico.zram[a&0x1fff]=data; return; }
|
||||
}
|
||||
|
||||
void z80_write16(unsigned short data, unsigned short a)
|
||||
{
|
||||
//dprintf("z80_write16");
|
||||
|
||||
z80_write((unsigned char) data,a);
|
||||
z80_write((unsigned char)(data>>8),(u16)(a+1));
|
||||
}
|
||||
|
704
Pico/Memory.s
Normal file
704
Pico/Memory.s
Normal file
|
@ -0,0 +1,704 @@
|
|||
@ memory handlers with banking support for SSF II - The New Challengers
|
||||
@ mostly based on Gens code
|
||||
|
||||
@ (c) Copyright 2006, notaz
|
||||
@ All Rights Reserved
|
||||
|
||||
|
||||
|
||||
.text
|
||||
|
||||
@ default jump tables
|
||||
|
||||
m_read8_def_table:
|
||||
.long m_read8_rom0 @ 0x000000 - 0x07FFFF
|
||||
.long m_read8_rom1 @ 0x080000 - 0x0FFFFF
|
||||
.long m_read8_rom2 @ 0x100000 - 0x17FFFF
|
||||
.long m_read8_rom3 @ 0x180000 - 0x1FFFFF
|
||||
.long m_read8_rom4 @ 0x200000 - 0x27FFFF
|
||||
.long m_read8_rom5 @ 0x280000 - 0x2FFFFF
|
||||
.long m_read8_rom6 @ 0x300000 - 0x37FFFF
|
||||
.long m_read8_rom7 @ 0x380000 - 0x3FFFFF
|
||||
.long m_read8_rom8 @ 0x400000 - 0x47FFFF
|
||||
.long m_read8_rom9 @ 0x480000 - 0x4FFFFF
|
||||
.long m_read8_romA @ 0x500000 - 0x57FFFF
|
||||
.long m_read8_romB @ 0x580000 - 0x5FFFFF
|
||||
.long m_read8_romC @ 0x600000 - 0x67FFFF
|
||||
.long m_read8_romD @ 0x680000 - 0x6FFFFF
|
||||
.long m_read8_romE @ 0x700000 - 0x77FFFF
|
||||
.long m_read8_romF @ 0x780000 - 0x7FFFFF
|
||||
.long m_read_null @ 0x800000 - 0x87FFFF
|
||||
.long m_read_null @ 0x880000 - 0x8FFFFF
|
||||
.long m_read_null @ 0x900000 - 0x97FFFF
|
||||
.long m_read_null @ 0x980000 - 0x9FFFFF
|
||||
.long m_read8_misc @ 0xA00000 - 0xA7FFFF
|
||||
.long m_read_null @ 0xA80000 - 0xAFFFFF
|
||||
.long m_read_null @ 0xB00000 - 0xB7FFFF
|
||||
.long m_read_null @ 0xB80000 - 0xBFFFFF
|
||||
.long m_read8_vdp @ 0xC00000 - 0xC7FFFF
|
||||
.long m_read8_vdp @ 0xC80000 - 0xCFFFFF
|
||||
.long m_read_null @ 0xD00000 - 0xD7FFFF
|
||||
.long m_read_null @ 0xD80000 - 0xDFFFFF
|
||||
.long m_read8_ram @ 0xE00000 - 0xE7FFFF
|
||||
.long m_read8_ram @ 0xE80000 - 0xEFFFFF
|
||||
.long m_read8_ram @ 0xF00000 - 0xF7FFFF
|
||||
.long m_read8_ram @ 0xF80000 - 0xFFFFFF
|
||||
|
||||
m_read16_def_table:
|
||||
.long m_read16_rom0 @ 0x000000 - 0x07FFFF
|
||||
.long m_read16_rom1 @ 0x080000 - 0x0FFFFF
|
||||
.long m_read16_rom2 @ 0x100000 - 0x17FFFF
|
||||
.long m_read16_rom3 @ 0x180000 - 0x1FFFFF
|
||||
.long m_read16_rom4 @ 0x200000 - 0x27FFFF
|
||||
.long m_read16_rom5 @ 0x280000 - 0x2FFFFF
|
||||
.long m_read16_rom6 @ 0x300000 - 0x37FFFF
|
||||
.long m_read16_rom7 @ 0x380000 - 0x3FFFFF
|
||||
.long m_read16_rom8 @ 0x400000 - 0x47FFFF
|
||||
.long m_read16_rom9 @ 0x480000 - 0x4FFFFF
|
||||
.long m_read16_romA @ 0x500000 - 0x57FFFF
|
||||
.long m_read16_romB @ 0x580000 - 0x5FFFFF
|
||||
.long m_read16_romC @ 0x600000 - 0x67FFFF
|
||||
.long m_read16_romD @ 0x680000 - 0x6FFFFF
|
||||
.long m_read16_romE @ 0x700000 - 0x77FFFF
|
||||
.long m_read16_romF @ 0x780000 - 0x7FFFFF
|
||||
.long m_read_null @ 0x800000 - 0x87FFFF
|
||||
.long m_read_null @ 0x880000 - 0x8FFFFF
|
||||
.long m_read_null @ 0x900000 - 0x97FFFF
|
||||
.long m_read_null @ 0x980000 - 0x9FFFFF
|
||||
.long m_read16_misc @ 0xA00000 - 0xA7FFFF
|
||||
.long m_read_null @ 0xA80000 - 0xAFFFFF
|
||||
.long m_read_null @ 0xB00000 - 0xB7FFFF
|
||||
.long m_read_null @ 0xB80000 - 0xBFFFFF
|
||||
.long m_read16_vdp @ 0xC00000 - 0xC7FFFF
|
||||
.long m_read_null @ 0xC80000 - 0xCFFFFF
|
||||
.long m_read_null @ 0xD00000 - 0xD7FFFF
|
||||
.long m_read_null @ 0xD80000 - 0xDFFFFF
|
||||
.long m_read16_ram @ 0xE00000 - 0xE7FFFF
|
||||
.long m_read16_ram @ 0xE80000 - 0xEFFFFF
|
||||
.long m_read16_ram @ 0xF00000 - 0xF7FFFF
|
||||
.long m_read16_ram @ 0xF80000 - 0xFFFFFF
|
||||
|
||||
m_read32_def_table:
|
||||
.long m_read32_rom0 @ 0x000000 - 0x07FFFF
|
||||
.long m_read32_rom1 @ 0x080000 - 0x0FFFFF
|
||||
.long m_read32_rom2 @ 0x100000 - 0x17FFFF
|
||||
.long m_read32_rom3 @ 0x180000 - 0x1FFFFF
|
||||
.long m_read32_rom4 @ 0x200000 - 0x27FFFF
|
||||
.long m_read32_rom5 @ 0x280000 - 0x2FFFFF
|
||||
.long m_read32_rom6 @ 0x300000 - 0x37FFFF
|
||||
.long m_read32_rom7 @ 0x380000 - 0x3FFFFF
|
||||
.long m_read32_rom8 @ 0x400000 - 0x47FFFF
|
||||
.long m_read32_rom9 @ 0x480000 - 0x4FFFFF
|
||||
.long m_read32_romA @ 0x500000 - 0x57FFFF
|
||||
.long m_read32_romB @ 0x580000 - 0x5FFFFF
|
||||
.long m_read32_romC @ 0x600000 - 0x67FFFF
|
||||
.long m_read32_romD @ 0x680000 - 0x6FFFFF
|
||||
.long m_read32_romE @ 0x700000 - 0x77FFFF
|
||||
.long m_read32_romF @ 0x780000 - 0x7FFFFF
|
||||
.long m_read_null @ 0x800000 - 0x87FFFF
|
||||
.long m_read_null @ 0x880000 - 0x8FFFFF
|
||||
.long m_read_null @ 0x900000 - 0x97FFFF
|
||||
.long m_read_null @ 0x980000 - 0x9FFFFF
|
||||
.long m_read32_misc @ 0xA00000 - 0xA7FFFF
|
||||
.long m_read_null @ 0xA80000 - 0xAFFFFF
|
||||
.long m_read_null @ 0xB00000 - 0xB7FFFF
|
||||
.long m_read_null @ 0xB80000 - 0xBFFFFF
|
||||
.long m_read32_vdp @ 0xC00000 - 0xC7FFFF
|
||||
.long m_read_null @ 0xC80000 - 0xCFFFFF
|
||||
.long m_read_null @ 0xD00000 - 0xD7FFFF
|
||||
.long m_read_null @ 0xD80000 - 0xDFFFFF
|
||||
.long m_read32_ram @ 0xE00000 - 0xE7FFFF
|
||||
.long m_read32_ram @ 0xE80000 - 0xEFFFFF
|
||||
.long m_read32_ram @ 0xF00000 - 0xF7FFFF
|
||||
.long m_read32_ram @ 0xF80000 - 0xFFFFFF
|
||||
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.bss
|
||||
@.section .bss, "brw"
|
||||
@.data
|
||||
|
||||
@ used tables
|
||||
m_read8_table:
|
||||
.skip 32*4
|
||||
|
||||
m_read16_table:
|
||||
.skip 32*4
|
||||
|
||||
m_read32_table:
|
||||
.skip 32*4
|
||||
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.text
|
||||
|
||||
.global PicoMemReset
|
||||
.global PicoRead8
|
||||
.global PicoRead16
|
||||
.global PicoRead32
|
||||
.global PicoWriteRomHW_SSF2
|
||||
|
||||
|
||||
PicoMemReset:
|
||||
ldr r12,=(Pico+0x22204)
|
||||
ldr r12,[r12] @ romsize
|
||||
add r12,r12,#0x80000
|
||||
sub r12,r12,#1
|
||||
mov r12,r12,lsr #19
|
||||
|
||||
ldr r0, =m_read8_table
|
||||
ldr r1, =m_read8_def_table
|
||||
mov r2, #32
|
||||
1:
|
||||
ldr r3, [r1], #4
|
||||
str r3, [r0], #4
|
||||
subs r2, r2, #1
|
||||
bne 1b
|
||||
|
||||
ldr r0, =m_read16_table
|
||||
ldr r1, =m_read16_def_table
|
||||
mov r2, #32
|
||||
1:
|
||||
subs r2, r2, #1
|
||||
ldr r3, [r1], #4
|
||||
str r3, [r0], #4
|
||||
bne 1b
|
||||
|
||||
ldr r0, =m_read32_table
|
||||
ldr r1, =m_read32_def_table
|
||||
mov r2, #32
|
||||
1:
|
||||
subs r2, r2, #1
|
||||
ldr r3, [r1], #4
|
||||
str r3, [r0], #4
|
||||
bne 1b
|
||||
|
||||
@ update memhandlers according to ROM size
|
||||
ldr r1, =m_read8_above_rom
|
||||
ldr r0, =m_read8_table
|
||||
mov r2, #16
|
||||
1:
|
||||
sub r2, r2, #1
|
||||
cmp r2, r12
|
||||
blt 2f
|
||||
cmp r2, #4
|
||||
beq 1b @ do not touch the SRAM area
|
||||
str r1, [r0, r2, lsl #2]
|
||||
b 1b
|
||||
2:
|
||||
ldr r1, =m_read16_above_rom
|
||||
ldr r0, =m_read16_table
|
||||
mov r2, #16
|
||||
1:
|
||||
sub r2, r2, #1
|
||||
cmp r2, r12
|
||||
blt 2f
|
||||
cmp r2, #4
|
||||
beq 1b
|
||||
str r1, [r0, r2, lsl #2]
|
||||
b 1b
|
||||
2:
|
||||
ldr r1, =m_read32_above_rom
|
||||
ldr r0, =m_read32_table
|
||||
mov r2, #16
|
||||
1:
|
||||
sub r2, r2, #1
|
||||
cmp r2, r12
|
||||
blt 2f
|
||||
cmp r2, #4
|
||||
beq 1b
|
||||
str r1, [r0, r2, lsl #2]
|
||||
b 1b
|
||||
2:
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
PicoRead8: @ u32 a
|
||||
ldr r2, =m_read8_table
|
||||
bic r0, r0, #0xff000000
|
||||
and r1, r0, #0x00f80000
|
||||
ldr pc, [r2, r1, lsr #17]
|
||||
|
||||
PicoRead16: @ u32 a
|
||||
ldr r2, =m_read16_table
|
||||
bic r0, r0, #0xff000000
|
||||
and r1, r0, #0x00f80000
|
||||
ldr pc, [r2, r1, lsr #17]
|
||||
|
||||
PicoRead32: @ u32 a
|
||||
ldr r2, =m_read32_table
|
||||
bic r0, r0, #0xff000000
|
||||
and r1, r0, #0x00f80000
|
||||
ldr pc, [r2, r1, lsr #17]
|
||||
|
||||
.pool
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
m_read_null:
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
|
||||
.macro m_read8_rom sect
|
||||
ldr r1, =(Pico+0x22200)
|
||||
bic r0, r0, #0xf80000
|
||||
ldr r1, [r1]
|
||||
.if \sect
|
||||
orr r0, r0, #0x080000*\sect
|
||||
.endif
|
||||
eor r0, r0, #1
|
||||
ldrb r0, [r1, r0]
|
||||
bx lr
|
||||
.endm
|
||||
|
||||
|
||||
m_read8_rom0: @ 0x000000 - 0x07ffff
|
||||
m_read8_rom 0
|
||||
|
||||
m_read8_rom1: @ 0x080000 - 0x0fffff
|
||||
m_read8_rom 1
|
||||
|
||||
m_read8_rom2: @ 0x100000 - 0x17ffff
|
||||
m_read8_rom 2
|
||||
|
||||
m_read8_rom3: @ 0x180000 - 0x1fffff
|
||||
m_read8_rom 3
|
||||
|
||||
m_read8_rom4: @ 0x200000 - 0x27ffff, SRAM area
|
||||
ldr r2, =(SRam)
|
||||
ldr r3, =(Pico+0x22200)
|
||||
ldr r1, [r2, #8] @ SRam.end
|
||||
bic r0, r0, #0xf80000
|
||||
orr r0, r0, #0x200000
|
||||
cmp r0, r1
|
||||
bgt m_read8_nosram
|
||||
ldr r1, [r2, #4] @ SRam.start (1ci)
|
||||
cmp r0, r1
|
||||
blt m_read8_nosram
|
||||
ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (1ci)
|
||||
sub r12,r0, #0x200000
|
||||
tst r1, #0x10
|
||||
bne m_read8_detected
|
||||
cmp r12,#1
|
||||
ble m_read8_detected
|
||||
tst r1, #1
|
||||
orrne r1, r1, #0x10
|
||||
strneb r1, [r3, #0x11]
|
||||
m_read8_detected:
|
||||
tst r1, #4 @ EEPROM read?
|
||||
ldrne r0, =SRAMReadEEPROM @ (1ci if ne)
|
||||
bxne r0
|
||||
m_read8_noteeprom:
|
||||
tst r1, #1
|
||||
beq m_read8_nosram
|
||||
ldr r3, [r2] @ SRam.data
|
||||
ldr r2, [r2, #4] @ SRam.start (1ci)
|
||||
sub r3, r3, r2
|
||||
ldrb r0, [r3, r0]
|
||||
bx lr
|
||||
m_read8_nosram:
|
||||
ldr r1, [r3, #4] @ 1ci
|
||||
cmp r0, r1
|
||||
movgt r0, #0
|
||||
bxgt lr @ bad location
|
||||
ldr r1, [r3]
|
||||
eor r0, r0, #1
|
||||
ldrb r0, [r1, r0]
|
||||
bx lr
|
||||
|
||||
m_read8_rom5: @ 0x280000 - 0x2fffff
|
||||
m_read8_rom 5
|
||||
|
||||
m_read8_rom6: @ 0x300000 - 0x37ffff
|
||||
m_read8_rom 6
|
||||
|
||||
m_read8_rom7: @ 0x380000 - 0x3fffff
|
||||
m_read8_rom 7
|
||||
|
||||
m_read8_rom8: @ 0x400000 - 0x47ffff
|
||||
m_read8_rom 8
|
||||
|
||||
m_read8_rom9: @ 0x480000 - 0x4fffff
|
||||
m_read8_rom 9
|
||||
|
||||
@ is any ROM using that much?
|
||||
m_read8_romA: @ 0x500000 - 0x57ffff
|
||||
m_read8_rom 0xA
|
||||
|
||||
m_read8_romB: @ 0x580000 - 0x5fffff
|
||||
m_read8_rom 0xB
|
||||
|
||||
m_read8_romC: @ 0x600000 - 0x67ffff
|
||||
m_read8_rom 0xC
|
||||
|
||||
m_read8_romD: @ 0x680000 - 0x6fffff
|
||||
m_read8_rom 0xD
|
||||
|
||||
m_read8_romE: @ 0x700000 - 0x77ffff
|
||||
m_read8_rom 0xE
|
||||
|
||||
m_read8_romF: @ 0x780000 - 0x7fffff
|
||||
m_read8_rom 0xF
|
||||
|
||||
m_read8_misc:
|
||||
bic r2, r0, #0x00ff
|
||||
bic r2, r2, #0xbf00
|
||||
cmp r2, #0xa00000 @ Z80 RAM?
|
||||
ldreq r2, =z80Read8
|
||||
bxeq r2
|
||||
stmfd sp!,{r0,lr}
|
||||
bic r0, r0, #1
|
||||
mov r1, #8
|
||||
bl OtherRead16
|
||||
ldmfd sp!,{r1,lr}
|
||||
tst r1, #1
|
||||
moveq r0, r0, lsr #8
|
||||
bx lr
|
||||
|
||||
m_read8_vdp:
|
||||
tst r0, #0x70000
|
||||
tsteq r0, #0x000e0
|
||||
bxne lr @ invalid read
|
||||
stmfd sp!,{r0,lr}
|
||||
bic r0, r0, #1
|
||||
bl PicoVideoRead
|
||||
ldmfd sp!,{r1,lr}
|
||||
tst r1, #1
|
||||
moveq r0, r0, lsr #8
|
||||
bx lr
|
||||
|
||||
m_read8_ram:
|
||||
ldr r1, =Pico
|
||||
bic r0, r0, #0xff0000
|
||||
eor r0, r0, #1
|
||||
ldrb r0, [r1, r0]
|
||||
bx lr
|
||||
|
||||
m_read8_above_rom:
|
||||
stmfd sp!,{r0,lr}
|
||||
bic r0, r0, #1
|
||||
mov r1, #8
|
||||
bl UnusualRead16
|
||||
ldmfd sp!,{r1,lr}
|
||||
tst r1, #1
|
||||
moveq r0, r0, lsr #8
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.macro m_read16_rom sect
|
||||
ldr r1, =(Pico+0x22200)
|
||||
bic r0, r0, #0xf80000
|
||||
ldr r1, [r1]
|
||||
bic r0, r0, #1
|
||||
.if \sect
|
||||
orr r0, r0, #0x080000*\sect
|
||||
.endif
|
||||
ldrh r0, [r1, r0]
|
||||
bx lr
|
||||
.endm
|
||||
|
||||
|
||||
m_read16_rom0: @ 0x000000 - 0x07ffff
|
||||
m_read16_rom 0
|
||||
|
||||
m_read16_rom1: @ 0x080000 - 0x0fffff
|
||||
m_read16_rom 1
|
||||
|
||||
m_read16_rom2: @ 0x100000 - 0x17ffff
|
||||
m_read16_rom 2
|
||||
|
||||
m_read16_rom3: @ 0x180000 - 0x1fffff
|
||||
m_read16_rom 3
|
||||
|
||||
m_read16_rom4: @ 0x200000 - 0x27ffff, SRAM area (NBA Live 95)
|
||||
ldr r2, =(SRam)
|
||||
ldr r3, =(Pico+0x22200)
|
||||
ldr r1, [r2, #8] @ SRam.end
|
||||
bic r0, r0, #0xf80000
|
||||
bic r0, r0, #1
|
||||
orr r0, r0, #0x200000
|
||||
cmp r0, r1
|
||||
bgt m_read16_nosram
|
||||
ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (2ci)
|
||||
tst r1, #1
|
||||
beq m_read16_nosram
|
||||
ldr r1, [r2, #4] @ SRam.start (1ci)
|
||||
cmp r0, r1
|
||||
blt m_read16_nosram
|
||||
ldr r2, [r2] @ SRam.data (1ci)
|
||||
sub r2, r2, r1
|
||||
ldrh r0, [r2, r0] @ 2ci
|
||||
and r1, r0, #0xff
|
||||
mov r0, r0, lsr #8
|
||||
orr r0, r0, r1, lsl #8
|
||||
bx lr
|
||||
m_read16_nosram:
|
||||
ldr r1, [r3, #4] @ 1ci
|
||||
cmp r0, r1
|
||||
movgt r0, #0
|
||||
bxgt lr @ bad location
|
||||
ldr r1, [r3] @ 1ci
|
||||
ldrh r0, [r1, r0]
|
||||
bx lr
|
||||
|
||||
m_read16_rom5: @ 0x280000 - 0x2fffff
|
||||
m_read16_rom 5
|
||||
|
||||
m_read16_rom6: @ 0x300000 - 0x37ffff
|
||||
m_read16_rom 6
|
||||
|
||||
m_read16_rom7: @ 0x380000 - 0x3fffff
|
||||
m_read16_rom 7
|
||||
|
||||
m_read16_rom8: @ 0x400000 - 0x47ffff
|
||||
m_read16_rom 8
|
||||
|
||||
m_read16_rom9: @ 0x480000 - 0x4fffff
|
||||
m_read16_rom 9
|
||||
|
||||
@ is any ROM using that much?
|
||||
m_read16_romA: @ 0x500000 - 0x57ffff
|
||||
m_read16_rom 0xA
|
||||
|
||||
m_read16_romB: @ 0x580000 - 0x5fffff
|
||||
m_read16_rom 0xB
|
||||
|
||||
m_read16_romC: @ 0x600000 - 0x67ffff
|
||||
m_read16_rom 0xC
|
||||
|
||||
m_read16_romD: @ 0x680000 - 0x6fffff
|
||||
m_read16_rom 0xD
|
||||
|
||||
m_read16_romE: @ 0x700000 - 0x77ffff
|
||||
m_read16_rom 0xE
|
||||
|
||||
m_read16_romF: @ 0x780000 - 0x7fffff
|
||||
m_read16_rom 0xF
|
||||
|
||||
m_read16_misc:
|
||||
mov r1, #16
|
||||
ldr r2, =OtherRead16
|
||||
bic r0, r0, #1
|
||||
bx r2
|
||||
|
||||
m_read16_vdp:
|
||||
tst r0, #0x70000
|
||||
tsteq r0, #0x000e0
|
||||
bxne lr @ invalid read
|
||||
ldr r1, =PicoVideoRead
|
||||
bic r0, r0, #1
|
||||
bx r1
|
||||
|
||||
m_read16_ram:
|
||||
ldr r1, =Pico
|
||||
bic r0, r0, #0xff0000
|
||||
bic r0, r0, #1
|
||||
ldrh r0, [r1, r0]
|
||||
bx lr
|
||||
|
||||
m_read16_above_rom:
|
||||
mov r1, #16
|
||||
ldr r2, =UnusualRead16
|
||||
bic r0, r0, #1
|
||||
bx r2
|
||||
|
||||
.pool
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.macro m_read32_rom sect
|
||||
ldr r1, =(Pico+0x22200)
|
||||
bic r0, r0, #0xf80000
|
||||
ldr r1, [r1]
|
||||
bic r0, r0, #1
|
||||
.if \sect
|
||||
orr r0, r0, #0x080000*\sect
|
||||
.endif
|
||||
ldrh r0, [r1, r0]!
|
||||
ldrh r1, [r1, #2] @ 1ci
|
||||
orr r0, r1, r0, lsl #16
|
||||
bx lr
|
||||
.endm
|
||||
|
||||
|
||||
m_read32_rom0: @ 0x000000 - 0x07ffff
|
||||
m_read32_rom 0
|
||||
|
||||
m_read32_rom1: @ 0x080000 - 0x0fffff
|
||||
m_read32_rom 1
|
||||
|
||||
m_read32_rom2: @ 0x100000 - 0x17ffff
|
||||
m_read32_rom 2
|
||||
|
||||
m_read32_rom3: @ 0x180000 - 0x1fffff
|
||||
m_read32_rom 3
|
||||
|
||||
m_read32_rom4: @ 0x200000 - 0x27ffff, SRAM area (does any game do long reads?)
|
||||
ldr r2, =(SRam)
|
||||
ldr r3, =(Pico+0x22200)
|
||||
ldr r1, [r2, #8] @ SRam.end
|
||||
bic r0, r0, #0xf80000
|
||||
bic r0, r0, #1
|
||||
orr r0, r0, #0x200000
|
||||
cmp r0, r1
|
||||
bgt m_read32_nosram
|
||||
ldrb r1, [r3, #0x11] @ Pico.m.sram_reg (2ci)
|
||||
tst r1, #1
|
||||
beq m_read32_nosram
|
||||
ldr r1, [r2, #4] @ SRam.start (1ci)
|
||||
cmp r0, r1
|
||||
blt m_read32_nosram
|
||||
ldr r2, [r2] @ SRam.data (1ci)
|
||||
sub r2, r2, r1
|
||||
ldrh r0, [r2, r0]! @ (1ci)
|
||||
ldrh r1, [r2, #2]
|
||||
orr r0, r0, r0, lsl #16
|
||||
mov r0, r0, ror #8
|
||||
mov r0, r0, lsl #16
|
||||
orr r0, r0, r1, lsr #8
|
||||
and r1, r1, #0xff
|
||||
orr r0, r0, r1, lsl #8
|
||||
bx lr
|
||||
m_read32_nosram:
|
||||
ldr r1, [r3, #4] @ (1ci)
|
||||
cmp r0, r1
|
||||
movgt r0, #0
|
||||
bxgt lr @ bad location
|
||||
ldr r1, [r3] @ (1ci)
|
||||
ldrh r0, [r1, r0]!
|
||||
ldrh r1, [r1, #2] @ (2ci)
|
||||
orr r0, r1, r0, lsl #16
|
||||
bx lr
|
||||
|
||||
m_read32_rom5: @ 0x280000 - 0x2fffff
|
||||
m_read32_rom 5
|
||||
|
||||
m_read32_rom6: @ 0x300000 - 0x37ffff
|
||||
m_read32_rom 6
|
||||
|
||||
m_read32_rom7: @ 0x380000 - 0x3fffff
|
||||
m_read32_rom 7
|
||||
|
||||
m_read32_rom8: @ 0x400000 - 0x47ffff
|
||||
m_read32_rom 8
|
||||
|
||||
m_read32_rom9: @ 0x480000 - 0x4fffff
|
||||
m_read32_rom 9
|
||||
|
||||
@ is any ROM using that much?
|
||||
m_read32_romA: @ 0x500000 - 0x57ffff
|
||||
m_read32_rom 0xA
|
||||
|
||||
m_read32_romB: @ 0x580000 - 0x5fffff
|
||||
m_read32_rom 0xB
|
||||
|
||||
m_read32_romC: @ 0x600000 - 0x67ffff
|
||||
m_read32_rom 0xC
|
||||
|
||||
m_read32_romD: @ 0x680000 - 0x6fffff
|
||||
m_read32_rom 0xD
|
||||
|
||||
m_read32_romE: @ 0x700000 - 0x77ffff
|
||||
m_read32_rom 0xE
|
||||
|
||||
m_read32_romF: @ 0x780000 - 0x7fffff
|
||||
m_read32_rom 0xF
|
||||
|
||||
m_read32_misc:
|
||||
bic r0, r0, #1
|
||||
stmfd sp!,{r0,lr}
|
||||
mov r1, #32
|
||||
bl OtherRead16
|
||||
mov r1, r0
|
||||
ldmfd sp!,{r0}
|
||||
stmfd sp!,{r1}
|
||||
add r0, r0, #2
|
||||
mov r1, #32
|
||||
bl OtherRead16
|
||||
ldmfd sp!,{r1,lr}
|
||||
orr r0, r0, r1, lsl #16
|
||||
bx lr
|
||||
|
||||
m_read32_vdp:
|
||||
tst r0, #0x70000
|
||||
tsteq r0, #0x000e0
|
||||
bxne lr @ invalid read
|
||||
bic r0, r0, #1
|
||||
stmfd sp!,{r0,lr}
|
||||
bl PicoVideoRead
|
||||
mov r1, r0
|
||||
ldmfd sp!,{r0}
|
||||
stmfd sp!,{r1}
|
||||
add r0, r0, #2
|
||||
bl PicoVideoRead
|
||||
ldmfd sp!,{r1,lr}
|
||||
orr r0, r0, r1, lsl #16
|
||||
bx lr
|
||||
|
||||
m_read32_ram:
|
||||
ldr r1, =Pico
|
||||
bic r0, r0, #0xff0000
|
||||
bic r0, r0, #1
|
||||
ldrh r0, [r1, r0]!
|
||||
ldrh r1, [r1, #2] @ 2ci
|
||||
orr r0, r1, r0, lsl #16
|
||||
bx lr
|
||||
|
||||
m_read32_above_rom:
|
||||
bic r0, r0, #1
|
||||
stmfd sp!,{r0,lr}
|
||||
mov r1, #32
|
||||
bl UnusualRead16
|
||||
mov r1, r0
|
||||
ldmfd sp!,{r0}
|
||||
stmfd sp!,{r1}
|
||||
add r0, r0, #2
|
||||
mov r1, #32
|
||||
bl UnusualRead16
|
||||
ldmfd sp!,{r1,lr}
|
||||
orr r0, r0, r1, lsl #16
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
PicoWriteRomHW_SSF2: @ u32 a, u32 d
|
||||
and r0, r0, #0xe
|
||||
movs r0, r0, lsr #1
|
||||
bne pwr_banking
|
||||
|
||||
@ sram register
|
||||
ldr r2, =(Pico+0x22211) @ Pico.m.sram_reg
|
||||
and r1, r1, #3
|
||||
strb r1, [r2]
|
||||
bx lr
|
||||
|
||||
pwr_banking:
|
||||
and r1, r1, #0x1f
|
||||
|
||||
ldr r3, =m_read8_def_table
|
||||
ldr r2, =m_read8_table
|
||||
ldr r12, [r3, r1, lsl #2]
|
||||
str r12, [r2, r0, lsl #2]
|
||||
|
||||
ldr r3, =m_read16_def_table
|
||||
ldr r2, =m_read16_table
|
||||
ldr r12, [r3, r1, lsl #2]
|
||||
str r12, [r2, r0, lsl #2]
|
||||
|
||||
ldr r3, =m_read32_def_table
|
||||
ldr r2, =m_read32_table
|
||||
ldr r12, [r3, r1, lsl #2]
|
||||
str r12, [r2, r0, lsl #2]
|
||||
|
||||
bx lr
|
305
Pico/Misc.c
Normal file
305
Pico/Misc.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
// H-counter table for hvcounter reads in 40col mode
|
||||
// based on Gens code
|
||||
const unsigned char hcounts_40[] = {
|
||||
0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,
|
||||
0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,
|
||||
0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,
|
||||
0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21,
|
||||
0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,
|
||||
0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,
|
||||
0x2f,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x35,
|
||||
0x36,0x36,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3c,0x3c,
|
||||
0x3d,0x3d,0x3d,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x41,0x41,0x42,0x42,0x42,0x43,
|
||||
0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x49,0x49,0x4a,
|
||||
0x4a,0x4a,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,
|
||||
0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x57,0x57,
|
||||
0x57,0x58,0x58,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5e,
|
||||
0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x64,0x64,0x64,
|
||||
0x65,0x65,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,
|
||||
0x6c,0x6c,0x6c,0x6d,0x6d,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x71,0x71,0x71,0x72,
|
||||
0x72,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x79,
|
||||
0x79,0x79,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,
|
||||
0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x86,0x86,
|
||||
0x86,0x87,0x87,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,
|
||||
0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x93,0x93,0x94,
|
||||
0x94,0x94,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,
|
||||
0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa1,0xa1,
|
||||
0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa8,
|
||||
0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xab,0xab,0xab,0xac,0xac,0xad,0xad,0xae,0xae,0xae,
|
||||
0xaf,0xaf,0xb0,0xb0,
|
||||
0xe4,0xe4,0xe4,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,
|
||||
0xea,0xeb,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,
|
||||
0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,
|
||||
0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xfe,
|
||||
0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x05,
|
||||
0x05,0x06,0x06,0x06,
|
||||
0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,
|
||||
0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,
|
||||
};
|
||||
|
||||
// H-counter table for hvcounter reads in 32col mode
|
||||
const unsigned char hcounts_32[] = {
|
||||
0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,
|
||||
0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x0f,0x10,
|
||||
0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15,
|
||||
0x15,0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,
|
||||
0x1b,0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20,
|
||||
0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x26,0x26,
|
||||
0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,
|
||||
0x2c,0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,0x31,0x31,
|
||||
0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x36,0x36,0x36,0x37,
|
||||
0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,0x3c,0x3c,
|
||||
0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,0x41,0x41,0x41,0x42,
|
||||
0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47,
|
||||
0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,
|
||||
0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52,
|
||||
0x53,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,0x58,0x58,
|
||||
0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,
|
||||
0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,
|
||||
0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69,
|
||||
0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,
|
||||
0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x74,0x74,
|
||||
0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79,
|
||||
0x7a,0x7a,0x7b,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,
|
||||
0x7f,0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85,
|
||||
0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,
|
||||
0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90,
|
||||
0x90,0x90,0x91,0x91,
|
||||
0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,0xec,0xec,0xec,0xed,
|
||||
0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf2,
|
||||
0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,
|
||||
0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,
|
||||
0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,
|
||||
0x03,0x04,0x04,0x04,
|
||||
0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,
|
||||
0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,
|
||||
};
|
||||
|
||||
// vcounter values for PicoFrameSimple
|
||||
const unsigned short vcounts[] = {
|
||||
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
|
||||
8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16,
|
||||
16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
|
||||
33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41,
|
||||
42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49,
|
||||
50, 50, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58,
|
||||
58, 59, 59, 60, 60, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
|
||||
67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 73, 74, 74, 75,
|
||||
75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 83, 83,
|
||||
84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91,
|
||||
92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99,100,
|
||||
100,101,101,102,102,103,104,104,105,105,106,106,107,107,108,108,
|
||||
109,109,110,110,111,111,112,112,113,114,114,115,115,116,116,117,
|
||||
117,118,118,119,119,120,120,121,121,122,122,123,124,124,125,125,
|
||||
126,126,127,127,128,128,129,129,130,130,131,131,132,132,133,133,
|
||||
134,135,135,136,136,137,137,138,138,139,139,140,140,141,141,142,
|
||||
142,143,143,144,145,145,146,146,147,147,148,148,149,149,150,150,
|
||||
151,151,152,152,153,153,154,155,155,156,156,157,157,158,158,159,
|
||||
159,160,160,161,161,162,162,163,163,164,164,165,166,166,167,167,
|
||||
168,168,169,169,170,170,171,171,172,172,173,173,174,174,175,176,
|
||||
176,177,177,178,178,179,179,180,180,181,181,182,182,183,183,184,
|
||||
184,185,186,186,187,187,188,188,189,189,190,190,191,191,192,192,
|
||||
193,193,194,194,195,195,196,197,197,198,198,199,199,200,200,201,
|
||||
201,202,202,203,203,204,204,205,205,206,207,207,208,208,209,209,
|
||||
210,210,211,211,212,212,213,213,214,214,215,215,216,217,217,218,
|
||||
218,219,219,220,220,221,221,222,222,223,223,224,224,225,225,226,
|
||||
226,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234,
|
||||
235,235,236,236,237,238,238,239,239,240,240,241,241,242,242,243,
|
||||
243,244,244,245,245,246,246,247,248,248,249,249,250,250,251,251,
|
||||
252,252,253,253,254,254,255,255,256,256,257,257,258,259,259,260,
|
||||
260,261,261,262,262,263,263,264,264,265,265,266,266,267,267,268,
|
||||
269,269,270,270,271,271,272,272,273,273,274,274,275,275,276,276,
|
||||
277,277,278,279,279,280,280,281,281,282,282,283,283,284,284,285,
|
||||
285,286,286,287,287,288,288,289,290,290,291,291,292,292,293,293,
|
||||
294,294,295,295,296,296,297,297,298,298,299,300,300,301,301,302,
|
||||
302,303,303,304,304,305,305,306,306,307,307,308,308,309,310,310,
|
||||
311,311,311,311,
|
||||
};
|
||||
|
||||
|
||||
// rarely used EEPROM SRAM code
|
||||
// known games which use this:
|
||||
// Wonder Boy in Monster World, Megaman - The Wily Wars (X24C01, 128 bytes)
|
||||
// NFL Quarterback Club*, Frank Thomas Big Hurt Baseball (X24C04?)
|
||||
// College Slam, Blockbuster World Video Game Championship II, NBA Jam (X24C04?)
|
||||
// HardBall '95
|
||||
|
||||
// the above sports games use addr 0x200000 for SCL line (handled in Memory.c)
|
||||
|
||||
unsigned int lastSSRamWrite = 0xffff0000;
|
||||
|
||||
// sram_reg: LAtd sela (L=pending SCL, A=pending SDA, t=type(1==uses 0x200000 for SCL and 2K bytes),
|
||||
// d=SRAM was detected (header or by access), s=started, e=save is EEPROM, l=old SCL, a=old SDA)
|
||||
void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA)
|
||||
{
|
||||
unsigned int sreg = Pico.m.sram_reg, saddr = Pico.m.sram_addr, scyc = Pico.m.sram_cycle, ssa = Pico.m.sram_slave;
|
||||
|
||||
//dprintf("[%02x]", d);
|
||||
sreg |= saddr&0xc000; // we store word count in add reg: dw?a aaaa ... (d=word count detected, w=words(0==use 2 words, else 1))
|
||||
saddr&=0x1fff;
|
||||
|
||||
if(sreg & d & 2) {
|
||||
// SCL was and is still high..
|
||||
if((sreg & 1) && !(d&1)) {
|
||||
// ..and SDA went low, means it's a start command, so clear internal addr reg and clock counter
|
||||
//dprintf("-start-");
|
||||
if(!(sreg&0x8000) && scyc >= 9) {
|
||||
if(scyc != 28) sreg |= 0x4000; // 1 word
|
||||
//dprintf("detected word count: %i", scyc==28 ? 2 : 1);
|
||||
sreg |= 0x8000;
|
||||
}
|
||||
//saddr = 0;
|
||||
scyc = 0;
|
||||
sreg |= 8;
|
||||
} else if(!(sreg & 1) && (d&1)) {
|
||||
// SDA went high == stop command
|
||||
//dprintf("-stop-");
|
||||
sreg &= ~8;
|
||||
}
|
||||
}
|
||||
else if((sreg & 8) && !(sreg & 2) && (d&2)) {
|
||||
// we are started and SCL went high - next cycle
|
||||
scyc++; // pre-increment
|
||||
if(sreg & 0x20) {
|
||||
// X24C02+
|
||||
if((ssa&1) && scyc == 18) {
|
||||
scyc = 9;
|
||||
saddr++; // next address in read mode
|
||||
if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask
|
||||
}
|
||||
else if((sreg&0x4000) && scyc == 27) scyc = 18;
|
||||
else if(scyc == 36) scyc = 27;
|
||||
} else {
|
||||
// X24C01
|
||||
if(scyc == 18) {
|
||||
scyc = 9; // wrap
|
||||
if(saddr&1) { saddr+=2; saddr&=0xff; } // next addr in read mode
|
||||
}
|
||||
}
|
||||
//dprintf("scyc: %i", scyc);
|
||||
}
|
||||
else if((sreg & 8) && (sreg & 2) && !(d&2)) {
|
||||
// we are started and SCL went low (falling edge)
|
||||
if(sreg & 0x20) {
|
||||
// X24C02+
|
||||
if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles
|
||||
else if( (!(sreg&0x4000) && scyc > 27) || ((sreg&0x4000) && scyc > 18) ) {
|
||||
if(!(ssa&1)) {
|
||||
// data write
|
||||
unsigned char *pm=SRam.data+saddr;
|
||||
*pm <<= 1; *pm |= d&1;
|
||||
if(scyc == 26 || scyc == 35) {
|
||||
saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented
|
||||
//dprintf("w done: %02x; addr inc: %x", *pm, saddr);
|
||||
}
|
||||
SRam.changed = 1;
|
||||
}
|
||||
} else if(scyc > 9) {
|
||||
if(!(ssa&1)) {
|
||||
// we latch another addr bit
|
||||
saddr<<=1;
|
||||
if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask
|
||||
saddr|=d&1;
|
||||
//if(scyc==17||scyc==26) dprintf("addr reg done: %x", saddr);
|
||||
}
|
||||
} else {
|
||||
// slave address
|
||||
ssa<<=1; ssa|=d&1;
|
||||
//if(scyc==8) dprintf("slave done: %x", ssa);
|
||||
}
|
||||
} else {
|
||||
// X24C01
|
||||
if(scyc == 9); // ACK cycle, do nothing
|
||||
else if(scyc > 9) {
|
||||
if(!(saddr&1)) {
|
||||
// data write
|
||||
unsigned char *pm=SRam.data+(saddr>>1);
|
||||
*pm <<= 1; *pm |= d&1;
|
||||
if(scyc == 17) {
|
||||
saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented
|
||||
//dprintf("addr inc: %x", saddr>>1);
|
||||
}
|
||||
SRam.changed = 1;
|
||||
}
|
||||
} else {
|
||||
// we latch another addr bit
|
||||
saddr<<=1; saddr|=d&1; saddr&=0xff;
|
||||
//if(scyc==8) dprintf("addr done: %x", saddr>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sreg &= ~3; sreg |= d&3; // remember SCL and SDA
|
||||
Pico.m.sram_reg = (unsigned char) sreg;
|
||||
Pico.m.sram_addr = (unsigned short)(saddr|(sreg&0xc000));
|
||||
Pico.m.sram_cycle= (unsigned char) scyc;
|
||||
Pico.m.sram_slave= (unsigned char) ssa;
|
||||
}
|
||||
|
||||
unsigned int SRAMReadEEPROM()
|
||||
{
|
||||
unsigned int shift, d=0;
|
||||
unsigned int sreg, saddr, scyc, ssa;
|
||||
|
||||
// flush last pending write
|
||||
SRAMWriteEEPROM(Pico.m.sram_reg>>6);
|
||||
|
||||
sreg = Pico.m.sram_reg; saddr = Pico.m.sram_addr&0x1fff; scyc = Pico.m.sram_cycle; ssa = Pico.m.sram_slave;
|
||||
// if(!(sreg & 2) && (sreg&0x80)) scyc++; // take care of raising edge now to compensate lag
|
||||
|
||||
if(SekCyclesDoneT()-lastSSRamWrite < 46) {
|
||||
// data was just written, there was no time to respond (used by sports games)
|
||||
d = (sreg>>6)&1;
|
||||
} else if((sreg & 8) && scyc > 9 && scyc != 18 && scyc != 27) {
|
||||
// started and first command word received
|
||||
shift = 17-scyc;
|
||||
if(sreg & 0x20) {
|
||||
// X24C02+
|
||||
if(ssa&1) {
|
||||
//dprintf("read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg);
|
||||
d = (SRam.data[saddr]>>shift)&1;
|
||||
}
|
||||
} else {
|
||||
// X24C01
|
||||
if(saddr&1) {
|
||||
d = (SRam.data[saddr>>1]>>shift)&1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//else dprintf("r ack");
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void SRAMUpdPending(unsigned int a, unsigned int d)
|
||||
{
|
||||
unsigned int sreg = Pico.m.sram_reg;
|
||||
|
||||
if(!(a&1)) sreg|=0x20;
|
||||
|
||||
if(sreg&0x20) { // address through 0x200000
|
||||
if(!(a&1)) {
|
||||
sreg&=~0x80;
|
||||
sreg|=d<<7;
|
||||
} else {
|
||||
sreg&=~0x40;
|
||||
sreg|=(d<<6)&0x40;
|
||||
}
|
||||
} else {
|
||||
sreg&=~0xc0;
|
||||
sreg|=d<<6;
|
||||
}
|
||||
|
||||
Pico.m.sram_reg = (unsigned char) sreg;
|
||||
}
|
661
Pico/Pico.c
Normal file
661
Pico/Pico.c
Normal file
|
@ -0,0 +1,661 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
#include "sound/sound.h"
|
||||
#include "sound/ym2612.h"
|
||||
|
||||
int PicoVer=0x0080;
|
||||
struct Pico Pico;
|
||||
int PicoOpt=0; // disable everything by default
|
||||
int PicoSkipFrame=0; // skip rendering frame?
|
||||
int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
|
||||
int emustatus = 0;
|
||||
void (*PicoWriteSound)(void) = 0; // called once per frame at the best time to send sound buffer (PsndOut) to hardware
|
||||
|
||||
struct PicoSRAM SRam;
|
||||
int z80startCycle = 0, z80stopCycle = 0; // in 68k cycles
|
||||
//int z80ExtraCycles = 0;
|
||||
int PicoPad[2]; // Joypads, format is SACB RLDU
|
||||
int PicoMCD = 0; // mega CD status
|
||||
|
||||
// to be called once on emu init
|
||||
int PicoInit(void)
|
||||
{
|
||||
// Blank space for state:
|
||||
memset(&Pico,0,sizeof(Pico));
|
||||
memset(&PicoPad,0,sizeof(PicoPad));
|
||||
|
||||
// Init CPUs:
|
||||
SekInit();
|
||||
z80_init(); // init even if we aren't going to use it
|
||||
|
||||
// Setup memory callbacks:
|
||||
PicoMemInit();
|
||||
|
||||
PicoInitMCD();
|
||||
|
||||
// notaz: sram
|
||||
SRam.data=0;
|
||||
SRam.resize=1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// to be called once on emu exit
|
||||
void PicoExit(void)
|
||||
{
|
||||
PicoExitMCD();
|
||||
z80_exit();
|
||||
|
||||
// notaz: sram
|
||||
if(SRam.data) free(SRam.data); SRam.data=0;
|
||||
}
|
||||
|
||||
int PicoReset(int hard)
|
||||
{
|
||||
unsigned int region=0;
|
||||
int support=0,hw=0,i=0;
|
||||
unsigned char pal=0;
|
||||
|
||||
if (Pico.romsize<=0) return 1;
|
||||
|
||||
PicoMemReset();
|
||||
SekReset();
|
||||
SekCycleCntT=0;
|
||||
z80_reset();
|
||||
|
||||
// reset VDP state, VRAM and PicoMisc
|
||||
//memset(&Pico.video,0,sizeof(Pico.video));
|
||||
//memset(&Pico.vram,0,sizeof(Pico.vram));
|
||||
memset(&Pico.m,0,sizeof(Pico.m));
|
||||
Pico.video.pending_ints=0;
|
||||
emustatus = 0;
|
||||
|
||||
if(hard) {
|
||||
// clear all memory of the emulated machine
|
||||
memset(&Pico.ram,0,(unsigned int)&Pico.rom-(unsigned int)&Pico.ram);
|
||||
}
|
||||
|
||||
// default VDP register values (based on Fusion)
|
||||
Pico.video.reg[0] = Pico.video.reg[1] = 0x04;
|
||||
Pico.video.reg[0xc] = 0x81;
|
||||
Pico.video.reg[0xf] = 0x02;
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
if(PicoRegionOverride)
|
||||
{
|
||||
support = PicoRegionOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read cartridge region data:
|
||||
region=PicoRead32(0x1f0);
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
{
|
||||
int c=0;
|
||||
|
||||
c=region>>(i<<3); c&=0xff;
|
||||
if (c<=' ') continue;
|
||||
|
||||
if (c=='J') support|=1;
|
||||
else if (c=='U') support|=4;
|
||||
else if (c=='E') support|=8;
|
||||
else
|
||||
{
|
||||
// New style code:
|
||||
char s[2]={0,0};
|
||||
s[0]=(char)c;
|
||||
support|=strtol(s,NULL,16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to pick the best hardware value for English/50hz:
|
||||
if (support&8) { hw=0xc0; pal=1; } // Europe
|
||||
else if (support&4) hw=0x80; // USA
|
||||
else if (support&2) { hw=0x40; pal=1; } // Japan PAL
|
||||
else if (support&1) hw=0x00; // Japan NTSC
|
||||
else hw=0x80; // USA
|
||||
|
||||
Pico.m.hardware=(unsigned char)(hw|0x20); // No disk attached
|
||||
Pico.m.pal=pal;
|
||||
Pico.video.status = 0x3408 | pal; // always set bits | vblank | pal
|
||||
|
||||
sound_reset(); // pal must be known here
|
||||
|
||||
if (PicoMCD & 1) {
|
||||
PicoResetMCD(hard);
|
||||
SRam.data = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// notaz: sram
|
||||
if(SRam.resize) {
|
||||
int sram_size = 0;
|
||||
if(SRam.data) free(SRam.data); SRam.data=0;
|
||||
Pico.m.sram_reg = 0;
|
||||
|
||||
if(*(Pico.rom+0x1B1) == 'R' && *(Pico.rom+0x1B0) == 'A') {
|
||||
if(*(Pico.rom+0x1B2) & 0x40) {
|
||||
// EEPROM SRAM
|
||||
// what kind of EEPROMs are actually used? X24C02? X24C04? (X24C01 has only 128), but we will support up to 8K
|
||||
SRam.start = PicoRead32(0x1B4) & ~1; // zero address is used for clock by some games
|
||||
SRam.end = PicoRead32(0x1B8);
|
||||
sram_size = 0x2000;
|
||||
Pico.m.sram_reg = 4;
|
||||
} else {
|
||||
// normal SRAM
|
||||
SRam.start = PicoRead32(0x1B4) & 0xFFFF00;
|
||||
SRam.end = PicoRead32(0x1B8) | 1;
|
||||
sram_size = SRam.end - SRam.start + 1;
|
||||
}
|
||||
Pico.m.sram_reg |= 0x10; // SRAM was detected
|
||||
}
|
||||
if(sram_size <= 0) {
|
||||
// some games may have bad headers, like S&K and Sonic3
|
||||
SRam.start = 0x200000;
|
||||
SRam.end = 0x203FFF;
|
||||
sram_size = 0x004000;
|
||||
}
|
||||
|
||||
// enable sram access by default if it doesn't overlap with ROM
|
||||
if(Pico.romsize <= SRam.start) Pico.m.sram_reg |= 1;
|
||||
SRam.reg_back = Pico.m.sram_reg;
|
||||
|
||||
if(sram_size) {
|
||||
SRam.data = (unsigned char *) calloc(sram_size, 1);
|
||||
if(!SRam.data) return 1;
|
||||
}
|
||||
SRam.resize=0;
|
||||
// Dino Dini's Soccer malfunctions if SRAM is not filled with 0xff
|
||||
if (strncmp((char *)Pico.rom+0x150, "IDOND NI'I", 10) == 0)
|
||||
memset(SRam.data, 0xff, sram_size);
|
||||
}
|
||||
|
||||
Pico.m.sram_reg = SRam.reg_back; // restore sram_reg
|
||||
SRam.changed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline void SekRun(int cyc)
|
||||
{
|
||||
int cyc_do;
|
||||
SekCycleAim+=cyc;
|
||||
if((cyc_do=SekCycleAim-SekCycleCnt) < 0) return;
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
// this means we do run-compare Cyclone vs Musashi
|
||||
SekCycleCnt+=CM_compareRun(cyc_do);
|
||||
#elif defined(EMU_C68K)
|
||||
PicoCpu.cycles=cyc_do;
|
||||
CycloneRun(&PicoCpu);
|
||||
SekCycleCnt+=cyc_do-PicoCpu.cycles;
|
||||
#elif defined(EMU_A68K)
|
||||
m68k_ICount=cyc_do;
|
||||
M68000_RUN();
|
||||
SekCycleCnt+=cyc_do-m68k_ICount;
|
||||
#elif defined(EMU_M68K)
|
||||
SekCycleCnt+=m68k_execute(cyc_do);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void SekStep(void)
|
||||
{
|
||||
// this is required for timing sensitive stuff to work
|
||||
int realaim=SekCycleAim; SekCycleAim=SekCycleCnt+1;
|
||||
#if defined(EMU_C68K) && defined(EMU_M68K)
|
||||
// this means we do run-compare Cyclone vs Musashi
|
||||
SekCycleCnt+=CM_compareRun(1);
|
||||
#elif defined(EMU_C68K)
|
||||
PicoCpu.cycles=1;
|
||||
CycloneRun(&PicoCpu);
|
||||
SekCycleCnt+=1-PicoCpu.cycles;
|
||||
#elif defined(EMU_A68K)
|
||||
m68k_ICount=1;
|
||||
M68000_RUN();
|
||||
SekCycleCnt+=1-m68k_ICount;
|
||||
#elif defined(EMU_M68K)
|
||||
SekCycleCnt+=m68k_execute(1);
|
||||
#endif
|
||||
SekCycleAim=realaim;
|
||||
}
|
||||
|
||||
static int CheckIdle(void)
|
||||
{
|
||||
#if 1
|
||||
unsigned char state[0x88];
|
||||
|
||||
memset(state,0,sizeof(state));
|
||||
|
||||
// See if the state is the same after 2 steps:
|
||||
SekState(state); SekStep(); SekStep(); SekState(state+0x44);
|
||||
if (memcmp(state,state+0x44,0x44)==0) return 1;
|
||||
#else
|
||||
unsigned char state[0x44];
|
||||
static unsigned char oldstate[0x44];
|
||||
|
||||
SekState(state);
|
||||
if(memcmp(state,oldstate,0x40)==0) return 1;
|
||||
memcpy(oldstate, state, 0x40);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// to be called on 224 or line_sample scanlines only
|
||||
static __inline void getSamples(int y)
|
||||
{
|
||||
if(y == 224) {
|
||||
//dprintf("sta%i: %i [%i]", (emustatus & 2), emustatus, y);
|
||||
if(emustatus & 2)
|
||||
sound_render(PsndLen/2, PsndLen-PsndLen/2);
|
||||
else sound_render(0, PsndLen);
|
||||
if (emustatus&1) emustatus|=2; else emustatus&=~2;
|
||||
if (PicoWriteSound) PicoWriteSound();
|
||||
// clear sound buffer
|
||||
memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));
|
||||
}
|
||||
else if(emustatus & 3) {
|
||||
emustatus|= 2;
|
||||
emustatus&=~1;
|
||||
sound_render(0, PsndLen/2);
|
||||
}
|
||||
}
|
||||
|
||||
//extern UINT32 mz80GetRegisterValue(void *, UINT32);
|
||||
|
||||
// Accurate but slower frame which does hints
|
||||
static int PicoFrameHints(void)
|
||||
{
|
||||
struct PicoVideo *pv=&Pico.video;
|
||||
int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample;
|
||||
const int cycles_68k=488,cycles_z80=228; // both PAL and NTSC compile to same values
|
||||
int skip=PicoSkipFrame || (PicoOpt&0x10);
|
||||
int hint; // Hint counter
|
||||
|
||||
if(Pico.m.pal) { //
|
||||
//cycles_68k = (int) ((double) OSC_PAL / 7 / 50 / 312 + 0.4); // should compile to a constant (488)
|
||||
//cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228
|
||||
lines = 312; // Steve Snake says there are 313 lines, but this seems to also work well
|
||||
line_sample = 68;
|
||||
if(pv->reg[1]&8) lines_vis = 240;
|
||||
} else {
|
||||
//cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488
|
||||
//cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
|
||||
lines = 262;
|
||||
line_sample = 93;
|
||||
}
|
||||
|
||||
SekCyclesReset();
|
||||
//z80ExtraCycles = 0;
|
||||
|
||||
if(PicoOpt&4)
|
||||
z80CycleAim = 0;
|
||||
// z80_resetCycles();
|
||||
|
||||
pv->status&=~0x88; // clear V-Int, come out of vblank
|
||||
|
||||
hint=pv->reg[10]; // Load H-Int counter
|
||||
//dprintf("-hint: %i", hint);
|
||||
|
||||
for (y=0;y<lines;y++)
|
||||
{
|
||||
Pico.m.scanline=(short)y;
|
||||
|
||||
// pad delay (for 6 button pads)
|
||||
if(PicoOpt&0x20) {
|
||||
if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0;
|
||||
if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0;
|
||||
}
|
||||
|
||||
// H-Interrupts:
|
||||
if(y <= lines_vis && --hint < 0) // y <= lines_vis: Comix Zone, Golden Axe
|
||||
{
|
||||
//dprintf("rhint:old @ %06x", SekPc);
|
||||
hint=pv->reg[10]; // Reload H-Int counter
|
||||
pv->pending_ints|=0x10;
|
||||
if (pv->reg[0]&0x10) SekInterrupt(4);
|
||||
//dprintf("rhint: %i @ %06x [%i|%i]", hint, SekPc, y, SekCycleCnt);
|
||||
//dprintf("hint_routine: %x", (*(unsigned short*)(Pico.ram+0x0B84)<<16)|*(unsigned short*)(Pico.ram+0x0B86));
|
||||
}
|
||||
|
||||
// V-Interrupt:
|
||||
if (y == lines_vis)
|
||||
{
|
||||
//dprintf("vint: @ %06x [%i|%i]", SekPc, y, SekCycleCnt);
|
||||
pv->status|=0x88; // V-Int happened, go into vblank
|
||||
SekRun(128); SekCycleAim-=128; // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula)
|
||||
/*if(Pico.m.z80Run && (PicoOpt&4)) {
|
||||
z80CycleAim+=cycles_z80/2;
|
||||
total_z80+=z80_run(z80CycleAim-total_z80);
|
||||
z80CycleAim-=cycles_z80/2;
|
||||
}*/
|
||||
pv->pending_ints|=0x20;
|
||||
if(pv->reg[1]&0x20) SekInterrupt(6);
|
||||
if(Pico.m.z80Run && (PicoOpt&4)) // ?
|
||||
z80_int();
|
||||
//dprintf("zint: [%i|%i] zPC=%04x", Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0));
|
||||
}
|
||||
|
||||
// decide if we draw this line
|
||||
#if CAN_HANDLE_240_LINES
|
||||
if(!skip && ((!(pv->reg[1]&8) && y<224) || ((pv->reg[1]&8) && y<240)) )
|
||||
#else
|
||||
if(!skip && y<224)
|
||||
#endif
|
||||
PicoLine(y);
|
||||
|
||||
if(PicoOpt&1)
|
||||
sound_timers_and_dac(y);
|
||||
|
||||
// get samples from sound chips
|
||||
if(y == 32 && PsndOut)
|
||||
emustatus &= ~1;
|
||||
else if((y == 224 || y == line_sample) && PsndOut)
|
||||
getSamples(y);
|
||||
|
||||
// Run scanline:
|
||||
SekRun(cycles_68k);
|
||||
if((PicoOpt&4) && Pico.m.z80Run) {
|
||||
Pico.m.z80Run|=2;
|
||||
z80CycleAim+=cycles_z80;
|
||||
total_z80+=z80_run(z80CycleAim-total_z80);
|
||||
}
|
||||
}
|
||||
|
||||
// draw a frame just after vblank in alternative render mode
|
||||
if(!PicoSkipFrame && (PicoOpt&0x10))
|
||||
PicoFrameFull();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// helper z80 runner
|
||||
static void PicoRunZ80Simple(int line_from, int line_to)
|
||||
{
|
||||
int line_from_r=line_from, line_to_r=line_to, line = line_from;
|
||||
int line_sample = Pico.m.pal ? 68 : 93;
|
||||
extern const unsigned short vcounts[];
|
||||
|
||||
if(!(PicoOpt&4) || Pico.m.z80Run == 0) { line_from_r = line_to_r; line_to_r = 0; }
|
||||
|
||||
if(z80startCycle != 0) {
|
||||
line_from_r = vcounts[z80startCycle>>8]+1;
|
||||
z80startCycle = 0;
|
||||
}
|
||||
if(z80stopCycle != 0) {
|
||||
line_to_r = vcounts[z80stopCycle>>8]+1;
|
||||
z80stopCycle = 0;
|
||||
}
|
||||
|
||||
if(PicoOpt&1) {
|
||||
// we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers
|
||||
for(; line < line_to; line++) {
|
||||
sound_timers_and_dac(line);
|
||||
if((line == 224 || line == line_sample) && PsndOut) getSamples(line);
|
||||
if(line == 32 && PsndOut) emustatus &= ~1;
|
||||
if(line >= line_from_r && line < line_to_r)
|
||||
z80_run(228);
|
||||
}
|
||||
} else if(line_to_r-line_from_r > 0) {
|
||||
z80_run(228*(line_to_r-line_from_r));
|
||||
// samples will be taken by caller
|
||||
}
|
||||
}
|
||||
|
||||
// Simple frame without H-Ints
|
||||
static int PicoFrameSimple(void)
|
||||
{
|
||||
struct PicoVideo *pv=&Pico.video;
|
||||
int y=0,line=0,lines=0,lines_step=0,sects;
|
||||
int cycles_68k_vblock,cycles_68k_block;
|
||||
|
||||
if(Pico.m.pal) {
|
||||
// M68k cycles/frame: 152009.78
|
||||
if(pv->reg[1]&8) { // 240 lines
|
||||
cycles_68k_block = (int) ((double) OSC_PAL / 7 / 50 / 312 * 15 + 0.4); // 16 sects, 16*15=240, 7308
|
||||
cycles_68k_vblock = (int) ((double) OSC_PAL / 7 / 50 / 312 * 24 + 0.4); // 3 sects, 3*24=72, 35163?
|
||||
lines_step = 15;
|
||||
} else {
|
||||
cycles_68k_block = (int) ((double) OSC_PAL / 7 / 50 / 312 * 14 + 0.4); // 16*14=224
|
||||
cycles_68k_vblock = (int) ((double) OSC_PAL / 7 / 50 / 312 * 22 + 0.4); // 4 sects, 4*22=88
|
||||
lines_step = 14;
|
||||
}
|
||||
} else {
|
||||
// M68k cycles/frame: 127840.71
|
||||
cycles_68k_block = (int) ((double) OSC_NTSC / 7 / 60 / 262 * 14 + 0.4); // 16*14=224, 6831
|
||||
cycles_68k_vblock = (int) ((double) OSC_NTSC / 7 / 60 / 262 * 19 + 0.4); // 2 sects, 2*19=38, 18544
|
||||
lines_step = 14;
|
||||
}
|
||||
|
||||
Pico.m.scanline=-1;
|
||||
|
||||
SekCyclesReset();
|
||||
|
||||
if(PicoOpt&4)
|
||||
z80_resetCycles();
|
||||
|
||||
// 6 button pad: let's just say it timed out now
|
||||
Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0;
|
||||
|
||||
// ---- Active Scan ----
|
||||
pv->status&=~88; // clear V-Int, come out of vblank
|
||||
|
||||
// Run in sections:
|
||||
for(sects=16; sects; sects--)
|
||||
{
|
||||
if (CheckIdle()) break;
|
||||
|
||||
lines += lines_step;
|
||||
SekRun(cycles_68k_block);
|
||||
|
||||
PicoRunZ80Simple(line, lines);
|
||||
line=lines;
|
||||
}
|
||||
|
||||
// run Z80 for remaining sections
|
||||
if(sects) {
|
||||
int c = sects*cycles_68k_block;
|
||||
|
||||
lines += sects*lines_step;
|
||||
PicoRunZ80Simple(line, lines);
|
||||
// this is for approriate line counter, etc
|
||||
SekCycleCnt += c;
|
||||
SekCycleAim += c;
|
||||
}
|
||||
|
||||
// here we render sound if ym2612 is disabled
|
||||
if(!(PicoOpt&1) && PsndOut) {
|
||||
sound_render(0, PsndLen);
|
||||
if(PicoWriteSound) PicoWriteSound();
|
||||
// clear sound buffer
|
||||
memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));
|
||||
}
|
||||
|
||||
// render screen
|
||||
if(!PicoSkipFrame) {
|
||||
if(!(PicoOpt&0x10))
|
||||
// Draw the screen
|
||||
#if CAN_HANDLE_240_LINES
|
||||
if(pv->reg[1]&8) {
|
||||
for (y=0;y<240;y++) PicoLine(y);
|
||||
} else {
|
||||
for (y=0;y<224;y++) PicoLine(y);
|
||||
}
|
||||
#else
|
||||
for (y=0;y<224;y++) PicoLine(y);
|
||||
#endif
|
||||
else PicoFrameFull();
|
||||
}
|
||||
|
||||
// ---- V-Blanking period ----
|
||||
// fix line counts
|
||||
if(Pico.m.pal) {
|
||||
if(pv->reg[1]&8) { // 240 lines
|
||||
lines = line = 240;
|
||||
sects = 3;
|
||||
lines_step = 24;
|
||||
} else {
|
||||
lines = line = 224;
|
||||
sects = 4;
|
||||
lines_step = 22;
|
||||
}
|
||||
} else {
|
||||
lines = line = 224;
|
||||
sects = 2;
|
||||
lines_step = 19;
|
||||
}
|
||||
|
||||
//dprintf("vint: @ %06x [%i]", SekPc, SekCycleCnt);
|
||||
pv->pending_ints|=0x20;
|
||||
if (pv->reg[1]&0x20) SekInterrupt(6); // Set IRQ
|
||||
pv->status|=0x88; // V-Int happened / go into vblank
|
||||
if(Pico.m.z80Run && (PicoOpt&4)) // ?
|
||||
z80_int();
|
||||
|
||||
while(sects) {
|
||||
lines += lines_step;
|
||||
|
||||
SekRun(cycles_68k_vblock);
|
||||
|
||||
PicoRunZ80Simple(line, lines);
|
||||
line=lines;
|
||||
|
||||
sects--;
|
||||
if(sects && CheckIdle()) break;
|
||||
}
|
||||
|
||||
// run Z80 for remaining sections
|
||||
if(sects) {
|
||||
lines += sects*lines_step;
|
||||
PicoRunZ80Simple(line, lines);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PicoFrame(void)
|
||||
{
|
||||
int acc;
|
||||
|
||||
if (PicoMCD & 1) {
|
||||
PicoFrameMCD();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// be accurate if we are asked for this
|
||||
if(PicoOpt&0x40) acc=1;
|
||||
// don't be accurate in alternative render mode, as hint effects will not be rendered anyway
|
||||
else if(PicoOpt&0x10) acc = 0;
|
||||
else acc=Pico.video.reg[0]&0x10; // be accurate if hints are used
|
||||
|
||||
//if(Pico.video.reg[12]&0x2) Pico.video.status ^= 0x10; // change odd bit in interlace mode
|
||||
|
||||
if(!(PicoOpt&0x10))
|
||||
PicoFrameStart();
|
||||
|
||||
if(acc)
|
||||
PicoFrameHints();
|
||||
else PicoFrameSimple();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DefaultCram(int cram)
|
||||
{
|
||||
int high=0x0841;
|
||||
// Convert 0000bbbb ggggrrrr
|
||||
// to rrrr1ggg g10bbbb1
|
||||
high|=(cram&0x00f)<<12; // Red
|
||||
high|=(cram&0x0f0)<< 3; // Green
|
||||
high|=(cram&0xf00)>> 7; // Blue
|
||||
return high;
|
||||
}
|
||||
|
||||
// Function to convert Megadrive Cram into a native colour:
|
||||
int (*PicoCram)(int cram)=DefaultCram;
|
||||
|
||||
#if defined(__DEBUG_PRINT) || defined(WIN32)
|
||||
// tmp debug: dump some stuff
|
||||
#define bit(r, x) ((r>>x)&1)
|
||||
void z80_debug(char *dstr);
|
||||
char *debugString()
|
||||
{
|
||||
#if 1
|
||||
static char dstr[1024];
|
||||
unsigned char *reg=Pico.video.reg, r;
|
||||
|
||||
// dump some info
|
||||
sprintf(dstr, "mode set 1: %02x\n", (r=reg[0]));
|
||||
sprintf(dstr, "%sdisplay_disable: %i, M3: %i, palette: %i, ?, hints: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,4));
|
||||
sprintf(dstr, "%smode set 2: %02x\n", dstr, (r=reg[1]));
|
||||
sprintf(dstr, "%sSMS/genesis: %i, pal: %i, dma: %i, vints: %i, disp: %i, TMS9918: %i\n\n",dstr, bit(r,2), bit(r,3), bit(r,4), bit(r,5), bit(r,6), bit(r,7));
|
||||
sprintf(dstr, "%smode set 3: %02x\n", dstr, (r=reg[0xB]));
|
||||
sprintf(dstr, "%sLSCR: %i, HSCR: %i, 2cell vscroll: %i, IE2: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,3));
|
||||
sprintf(dstr, "%smode set 4: %02x\n", dstr, (r=reg[0xC]));
|
||||
sprintf(dstr, "%sinterlace: %i%i; cells: %i; shadow: %i\n\n", dstr, bit(r,2), bit(r,1), (r&0x80) ? 40 : 32, bit(r,3));
|
||||
sprintf(dstr, "%sscroll size: w: %i; h: %i\n\n", dstr, reg[0x10]&3, (reg[0x10]&0x30)>>4);
|
||||
sprintf(dstr, "%sSRAM: det: %i; eeprom: %i\n", dstr, bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2));
|
||||
sprintf(dstr, "%sCPU state: PC: %06x cycles: %i\n", dstr, SekPc, SekCyclesDoneT());
|
||||
#ifdef EMU_C68K
|
||||
for(r=0; r < 8; r++)
|
||||
sprintf(dstr, "%sd%i=%08x, a%i=%08x\n", dstr, r, PicoCpu.d[r], r, PicoCpu.a[r]);
|
||||
#endif
|
||||
z80_debug(dstr);
|
||||
|
||||
#else
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int table=0;
|
||||
int i,u,n,link=0;
|
||||
static char dstr[1024*8];
|
||||
dstr[0] = 0;
|
||||
|
||||
table=pvid->reg[5]&0x7f;
|
||||
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
|
||||
table<<=8; // Get sprite table address/2
|
||||
|
||||
for (i=u=n=0; u < 80 && n < 20; u++)
|
||||
{
|
||||
unsigned int *sprite;
|
||||
int code, code2, sx, sy, height;
|
||||
|
||||
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
|
||||
|
||||
// get sprite info
|
||||
code = sprite[0];
|
||||
|
||||
// check if it is on this line
|
||||
sy = (code&0x1ff);//-0x80;
|
||||
height = ((code>>24)&3)+1;
|
||||
|
||||
// masking sprite?
|
||||
code2 = sprite[1];
|
||||
sx = (code2>>16)&0x1ff;
|
||||
|
||||
dprintf("#%02i x: %03i y: %03i %ix%i", u, sx, sy, ((code>>26)&3)+1, height);
|
||||
|
||||
link=(code>>16)&0x7f;
|
||||
if(!link) break; // End of sprites
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
{
|
||||
FILE *f = fopen("zram", "wb");
|
||||
fwrite(Pico.zram, 1, 0x2000, f);
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
return dstr;
|
||||
}
|
||||
#endif
|
96
Pico/Pico.h
Normal file
96
Pico/Pico.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
|
||||
// -------------------- Pico Library --------------------
|
||||
|
||||
// Pico Library - Header File
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#ifndef PICO_H
|
||||
#define PICO_H
|
||||
|
||||
// port-specific compile-time settings
|
||||
#include <port_config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Pico.c
|
||||
// PicoOpt bits LSb->MSb:
|
||||
// enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound,
|
||||
// alt_renderer, 6button_gamepad, accurate_timing, accurate_sprites,
|
||||
// draw_no_32col_border, external_ym2612
|
||||
extern int PicoOpt;
|
||||
extern int PicoVer;
|
||||
extern int PicoSkipFrame; // skip rendering frame, but still do sound (if enabled) and emulation stuff
|
||||
extern int PicoRegionOverride; // override the region detection 0: auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
|
||||
int PicoInit(void);
|
||||
void PicoExit(void);
|
||||
int PicoReset(int hard);
|
||||
int PicoFrame(void);
|
||||
extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU
|
||||
extern int (*PicoCram)(int cram); // Callback to convert colour ram 0000bbb0 ggg0rrr0
|
||||
extern void (*PicoWriteSound)(void); // called once per frame at the best time to send sound buffer (PsndOut) to hardware
|
||||
|
||||
int PicoFrameMCD(void);
|
||||
|
||||
// Area.c
|
||||
typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);
|
||||
// Save or load the state from PmovFile:
|
||||
int PmovState(int PmovAction, void *PmovFile); // &1=for reading &2=for writing &4=volatile &8=non-volatile
|
||||
extern arearw *areaRead; // read and write function pointers for
|
||||
extern arearw *areaWrite; // gzip save state ability
|
||||
|
||||
// Cart.c
|
||||
int PicoCartLoad(FILE *f,unsigned char **prom,unsigned int *psize);
|
||||
int PicoCartInsert(unsigned char *rom,unsigned int romsize);
|
||||
// notaz
|
||||
int CartLoadZip(const char *fname, unsigned char **prom, unsigned int *psize);
|
||||
void Byteswap(unsigned char *data,int len);
|
||||
// anotherguest
|
||||
int PicoUnloadCart(unsigned char* romdata);
|
||||
|
||||
// Draw.c
|
||||
void PicoDrawSetColorFormat(int which); // 0=BGR444, 1=RGB555, 2=8bit(HighPal pal)
|
||||
extern void *DrawLineDest;
|
||||
extern int (*PicoScan)(unsigned int num, void *data);
|
||||
// internals
|
||||
extern unsigned short HighPal[0x100];
|
||||
extern int rendstatus;
|
||||
// utility
|
||||
#ifdef _ASM_DRAW_C
|
||||
void *blockcpy(void *dst, const void *src, size_t n);
|
||||
#else
|
||||
#define blockcpy memcpy
|
||||
#endif
|
||||
|
||||
// Draw2.c
|
||||
// stuff below is optional
|
||||
extern unsigned short *PicoCramHigh; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
|
||||
extern void (*PicoPrepareCram)(); // prepares PicoCramHigh for renderer to use
|
||||
|
||||
// sound.c
|
||||
extern int PsndRate,PsndLen;
|
||||
extern short *PsndOut;
|
||||
void sound_reset();
|
||||
void sound_rerate();
|
||||
void z80_pack(unsigned char *data);
|
||||
void z80_unpack(unsigned char *data);
|
||||
void z80_reset();
|
||||
|
||||
// Utils.c
|
||||
extern int PicuAnd;
|
||||
int PicuQuick(unsigned short *dest,unsigned short *src);
|
||||
int PicuShrink(unsigned short *dest,int destLen,unsigned short *src,int srcLen);
|
||||
int PicuShrinkReverse(unsigned short *dest,int destLen,unsigned short *src,int srcLen);
|
||||
int PicuMerge(unsigned short *dest,int destLen,unsigned short *src,int srcLen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // End of extern "C"
|
||||
#endif
|
||||
|
||||
#endif // PICO_H
|
240
Pico/PicoInt.h
Normal file
240
Pico/PicoInt.h
Normal file
|
@ -0,0 +1,240 @@
|
|||
// Pico Library - Header File
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "Pico.h"
|
||||
|
||||
|
||||
// to select core, define EMU_C68K, EMU_M68K or EMU_A68K in your makefile
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// ----------------------- 68000 CPU -----------------------
|
||||
#ifdef EMU_C68K
|
||||
#include "../cpu/Cyclone/Cyclone.h"
|
||||
extern struct Cyclone PicoCpu;
|
||||
#define SekCyclesLeft PicoCpu.cycles // cycles left for this run
|
||||
#define SekSetCyclesLeft(c) PicoCpu.cycles=c
|
||||
#define SekPc (PicoCpu.pc-PicoCpu.membase)
|
||||
#endif
|
||||
|
||||
#ifdef EMU_A68K
|
||||
void __cdecl M68000_RUN();
|
||||
// The format of the data in a68k.asm (at the _M68000_regs location)
|
||||
struct A68KContext
|
||||
{
|
||||
unsigned int d[8],a[8];
|
||||
unsigned int isp,srh,ccr,xc,pc,irq,sr;
|
||||
int (*IrqCallback) (int nIrq);
|
||||
unsigned int ppc;
|
||||
void *pResetCallback;
|
||||
unsigned int sfc,dfc,usp,vbr;
|
||||
unsigned int AsmBank,CpuVersion;
|
||||
};
|
||||
struct A68KContext M68000_regs;
|
||||
extern int m68k_ICount;
|
||||
#define SekCyclesLeft m68k_ICount
|
||||
#define SekSetCyclesLeft(c) m68k_ICount=c
|
||||
#define SekPc M68000_regs.pc
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
#include "../cpu/musashi/m68kcpu.h"
|
||||
extern m68ki_cpu_core PicoM68kCPU; // MD's CPU
|
||||
extern m68ki_cpu_core PicoS68kCPU; // Mega CD's CPU
|
||||
#ifndef SekCyclesLeft
|
||||
#define SekCyclesLeft m68k_cycles_remaining()
|
||||
#define SekSetCyclesLeft(c) SET_CYCLES(c)
|
||||
#define SekPc m68k_get_reg(&PicoM68kCPU, M68K_REG_PC)
|
||||
#define SekPcS68k m68k_get_reg(&PicoS68kCPU, M68K_REG_PC)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern int SekCycleCnt; // cycles done in this frame
|
||||
extern int SekCycleAim; // cycle aim
|
||||
extern unsigned int SekCycleCntT; // total cycle counter, updated once per frame
|
||||
|
||||
#define SekCyclesReset() {SekCycleCntT+=SekCycleCnt;SekCycleCnt=SekCycleAim=0;}
|
||||
#define SekCyclesBurn(c) SekCycleCnt+=c
|
||||
#define SekCyclesDone() (SekCycleAim-SekCyclesLeft) // nuber of cycles done in this frame (can be checked anywhere)
|
||||
#define SekCyclesDoneT() (SekCycleCntT+SekCyclesDone()) // total nuber of cycles done for this rom
|
||||
|
||||
#define SekEndRun(after) { \
|
||||
SekCycleCnt -= SekCyclesLeft - after; \
|
||||
if(SekCycleCnt < 0) SekCycleCnt = 0; \
|
||||
SekSetCyclesLeft(after); \
|
||||
}
|
||||
|
||||
extern int SekCycleCntS68k;
|
||||
extern int SekCycleAimS68k;
|
||||
|
||||
#define SekCyclesResetS68k() {SekCycleCntS68k=SekCycleAimS68k=0;}
|
||||
|
||||
// does not work as expected
|
||||
//extern int z80ExtraCycles; // extra z80 cycles, used when z80 is [en|dis]abled
|
||||
|
||||
extern int PicoMCD;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
// main oscillator clock which controls timing
|
||||
#define OSC_NTSC 53693100
|
||||
#define OSC_PAL 53203424 // not accurate
|
||||
|
||||
struct PicoVideo
|
||||
{
|
||||
unsigned char reg[0x20];
|
||||
unsigned int command; // 32-bit Command
|
||||
unsigned char pending; // 1 if waiting for second half of 32-bit command
|
||||
unsigned char type; // Command type (v/c/vsram read/write)
|
||||
unsigned short addr; // Read/Write address
|
||||
int status; // Status bits
|
||||
unsigned char pending_ints; // pending interrupts: ??VH????
|
||||
unsigned char pad[0x13];
|
||||
};
|
||||
|
||||
struct PicoMisc
|
||||
{
|
||||
unsigned char rotate;
|
||||
unsigned char z80Run;
|
||||
unsigned char padTHPhase[2]; // phase of gamepad TH switches
|
||||
short scanline; // 0 to 261||311; -1 in fast mode
|
||||
char dirtyPal; // Is the palette dirty (1 - change @ this frame, 2 - some time before)
|
||||
unsigned char hardware; // Hardware value for country
|
||||
unsigned char pal; // 1=PAL 0=NTSC
|
||||
unsigned char sram_reg; // SRAM mode register. bit0: allow read? bit1: deny write? bit2: EEPROM?
|
||||
unsigned short z80_bank68k;
|
||||
unsigned short z80_lastaddr; // this is for Z80 faking
|
||||
unsigned char z80_fakeval;
|
||||
unsigned char pad0;
|
||||
unsigned char padDelay[2]; // gamepad phase time outs, so we count a delay
|
||||
unsigned short sram_addr; // EEPROM address register
|
||||
unsigned char sram_cycle; // EEPROM SRAM cycle number
|
||||
unsigned char sram_slave; // EEPROM slave word for X24C02 and better SRAMs
|
||||
unsigned char prot_bytes[2]; // simple protection fakeing
|
||||
unsigned char pad1[8];
|
||||
};
|
||||
|
||||
// some assembly stuff depend on these, do not touch!
|
||||
struct Pico
|
||||
{
|
||||
unsigned char ram[0x10000]; // 0x00000 scratch ram
|
||||
unsigned short vram[0x8000]; // 0x10000
|
||||
unsigned char zram[0x2000]; // 0x20000 Z80 ram
|
||||
unsigned char ioports[0x10];
|
||||
unsigned int pad[0x3c]; // unused
|
||||
unsigned short cram[0x40]; // 0x22100
|
||||
unsigned short vsram[0x40]; // 0x22180
|
||||
|
||||
unsigned char *rom; // 0x22200
|
||||
unsigned int romsize; // 0x22204
|
||||
|
||||
struct PicoMisc m;
|
||||
struct PicoVideo video;
|
||||
};
|
||||
|
||||
// sram
|
||||
struct PicoSRAM
|
||||
{
|
||||
unsigned char *data; // actual data
|
||||
unsigned int start; // start address in 68k address space
|
||||
unsigned int end;
|
||||
unsigned char resize; // 1=SRAM size changed and needs to be reallocated on PicoReset
|
||||
unsigned char reg_back; // copy of Pico.m.sram_reg to set after reset
|
||||
unsigned char changed;
|
||||
unsigned char pad;
|
||||
};
|
||||
|
||||
// MCD
|
||||
#include "cd/cd_sys.h"
|
||||
#include "cd/LC89510.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char bios[0x20000];
|
||||
union {
|
||||
unsigned char prg_ram[0x80000];
|
||||
unsigned char prg_ram_b[4][0x20000];
|
||||
};
|
||||
unsigned char word_ram[0x40000];
|
||||
unsigned char s68k_regs[0x200];
|
||||
unsigned char m68k_regs[0x10];
|
||||
CDD cdd;
|
||||
CDC cdc;
|
||||
_scd scd;
|
||||
} mcd_state;
|
||||
|
||||
#define Pico_mcd ((mcd_state *)Pico.rom)
|
||||
|
||||
|
||||
// Draw.c
|
||||
int PicoLine(int scan);
|
||||
void PicoFrameStart();
|
||||
|
||||
// Draw2.c
|
||||
void PicoFrameFull();
|
||||
|
||||
// Memory.c
|
||||
int PicoInitPc(unsigned int pc);
|
||||
unsigned int CPU_CALL PicoRead32(unsigned int a);
|
||||
int PicoMemInit();
|
||||
void PicoMemReset();
|
||||
void PicoDasm(int start,int len);
|
||||
unsigned char z80_read(unsigned short a);
|
||||
unsigned short z80_read16(unsigned short a);
|
||||
void z80_write(unsigned char data, unsigned short a);
|
||||
void z80_write16(unsigned short data, unsigned short a);
|
||||
|
||||
// cd/Memory.c
|
||||
unsigned char PicoReadCD8 (unsigned int a);
|
||||
unsigned short PicoReadCD16(unsigned int a);
|
||||
unsigned int PicoReadCD32(unsigned int a);
|
||||
void PicoWriteCD8 (unsigned int a, unsigned char d);
|
||||
void PicoWriteCD16(unsigned int a, unsigned short d);
|
||||
void PicoWriteCD32(unsigned int a, unsigned int d);
|
||||
|
||||
// Pico.c
|
||||
extern struct Pico Pico;
|
||||
extern struct PicoSRAM SRam;
|
||||
extern int emustatus;
|
||||
|
||||
// cd/Pico.c
|
||||
int PicoInitMCD(void);
|
||||
void PicoExitMCD(void);
|
||||
int PicoResetMCD(int hard);
|
||||
|
||||
// Sek.c
|
||||
int SekInit(void);
|
||||
int SekReset(void);
|
||||
int SekInterrupt(int irq);
|
||||
void SekState(unsigned char *data);
|
||||
|
||||
// cd/Sek.c
|
||||
int SekInitS68k(void);
|
||||
int SekResetS68k(void);
|
||||
int SekInterruptS68k(int irq);
|
||||
|
||||
// VideoPort.c
|
||||
void PicoVideoWrite(unsigned int a,unsigned short d);
|
||||
unsigned int PicoVideoRead(unsigned int a);
|
||||
|
||||
// Misc.c
|
||||
void SRAMWriteEEPROM(unsigned int d);
|
||||
unsigned int SRAMReadEEPROM();
|
||||
void SRAMUpdPending(unsigned int a, unsigned int d);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // End of extern "C"
|
||||
#endif
|
192
Pico/Sek.c
Normal file
192
Pico/Sek.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
|
||||
int SekCycleCnt=0; // cycles done in this frame
|
||||
int SekCycleAim=0; // cycle aim
|
||||
unsigned int SekCycleCntT=0;
|
||||
|
||||
#ifdef EMU_C68K
|
||||
// ---------------------- Cyclone 68000 ----------------------
|
||||
struct Cyclone PicoCpu;
|
||||
#endif
|
||||
|
||||
#ifdef EMU_M68K
|
||||
// ---------------------- MUSASHI 68000 ----------------------
|
||||
m68ki_cpu_core PicoM68kCPU; // MD's CPU
|
||||
#endif
|
||||
|
||||
#ifdef EMU_A68K
|
||||
// ---------------------- A68K ----------------------
|
||||
|
||||
void __cdecl M68000_RESET();
|
||||
int m68k_ICount=0;
|
||||
unsigned int mem_amask=0xffffff; // 24-bit bus
|
||||
unsigned int mame_debug=0,cur_mrhard=0,m68k_illegal_opcode=0,illegal_op=0,illegal_pc=0,opcode_entry=0; // filler
|
||||
|
||||
static int IrqCallback(int i) { i; return -1; }
|
||||
static int DoReset() { return 0; }
|
||||
static int (*ResetCallback)()=DoReset;
|
||||
|
||||
#pragma warning (disable:4152)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// interrupt acknowledgment
|
||||
#ifdef EMU_C68K
|
||||
static void SekIntAck(int level)
|
||||
{
|
||||
// try to emulate VDP's reaction to 68000 int ack
|
||||
if (level == 4) Pico.video.pending_ints = 0;
|
||||
else if(level == 6) Pico.video.pending_ints &= ~0x20;
|
||||
PicoCpu.irq = 0;
|
||||
}
|
||||
|
||||
static void SekResetAck()
|
||||
{
|
||||
#if defined(__DEBUG_PRINT) || defined(WIN32)
|
||||
dprintf("Reset encountered @ %06x", SekPc);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int SekUnrecognizedOpcode()
|
||||
{
|
||||
unsigned int pc, op;
|
||||
pc = SekPc;
|
||||
op = PicoCpu.read16(pc);
|
||||
#if defined(__DEBUG_PRINT) || defined(WIN32)
|
||||
dprintf("Unrecognized Opcode %04x @ %06x", op, pc);
|
||||
#endif
|
||||
// see if we are not executing trash
|
||||
if (pc < 0x200 || (pc > Pico.romsize+4 && (pc&0xe00000)!=0xe00000)) {
|
||||
PicoCpu.cycles = 0;
|
||||
PicoCpu.stopped = 1;
|
||||
return 1;
|
||||
}
|
||||
//exit(1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EMU_M68K
|
||||
static int SekIntAckM68K(int level)
|
||||
{
|
||||
if (level == 4) { Pico.video.pending_ints = 0; } // dprintf("hack: [%i|%i]", Pico.m.scanline, SekCyclesDone()); }
|
||||
else if(level == 6) { Pico.video.pending_ints &= ~0x20; } // dprintf("vack: [%i|%i]", Pico.m.scanline, SekCyclesDone()); }
|
||||
CPU_INT_LEVEL = 0;
|
||||
return M68K_INT_ACK_AUTOVECTOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int SekInit()
|
||||
{
|
||||
#ifdef EMU_C68K
|
||||
CycloneInit();
|
||||
memset(&PicoCpu,0,sizeof(PicoCpu));
|
||||
PicoCpu.IrqCallback=SekIntAck;
|
||||
PicoCpu.ResetCallback=SekResetAck;
|
||||
PicoCpu.UnrecognizedCallback=SekUnrecognizedOpcode;
|
||||
#endif
|
||||
#ifdef EMU_A68K
|
||||
memset(&M68000_regs,0,sizeof(M68000_regs));
|
||||
M68000_regs.IrqCallback=IrqCallback;
|
||||
M68000_regs.pResetCallback=ResetCallback;
|
||||
M68000_RESET(); // Init cpu emulator
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoM68kCPU);
|
||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
m68k_init();
|
||||
m68k_set_int_ack_callback(SekIntAckM68K);
|
||||
m68k_pulse_reset(); // Init cpu emulator
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset the 68000:
|
||||
int SekReset()
|
||||
{
|
||||
if (Pico.rom==NULL) return 1;
|
||||
|
||||
#ifdef EMU_C68K
|
||||
PicoCpu.stopped=0;
|
||||
PicoCpu.osp=0;
|
||||
PicoCpu.srh =0x27; // Supervisor mode
|
||||
PicoCpu.flags=4; // Z set
|
||||
PicoCpu.irq=0;
|
||||
PicoCpu.a[7]=PicoCpu.read32(0); // Stack Pointer
|
||||
PicoCpu.membase=0;
|
||||
PicoCpu.pc=PicoCpu.checkpc(PicoCpu.read32(4)); // Program Counter
|
||||
#endif
|
||||
#ifdef EMU_A68K
|
||||
// Reset CPU: fetch SP and PC
|
||||
M68000_regs.srh=0x27; // Supervisor mode
|
||||
M68000_regs.a[7]=PicoRead32(0);
|
||||
M68000_regs.pc =PicoRead32(4);
|
||||
PicoInitPc(M68000_regs.pc);
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoM68kCPU);
|
||||
m68k_pulse_reset();
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SekInterrupt(int irq)
|
||||
{
|
||||
#ifdef EMU_C68K
|
||||
PicoCpu.irq=irq;
|
||||
#endif
|
||||
#ifdef EMU_A68K
|
||||
M68000_regs.irq=irq; // raise irq (gets lowered after taken)
|
||||
#endif
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoM68kCPU);
|
||||
m68k_set_irq(irq); // raise irq (gets lowered after taken or must be done in ack)
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int SekPc() { return PicoCpu.pc-PicoCpu.membase; }
|
||||
//int SekPc() { return M68000_regs.pc; }
|
||||
//int SekPc() { return m68k_get_reg(NULL, M68K_REG_PC); }
|
||||
|
||||
void SekState(unsigned char *data)
|
||||
{
|
||||
#ifdef EMU_C68K
|
||||
memcpy(data,PicoCpu.d,0x44);
|
||||
#elif defined(EMU_A68K)
|
||||
memcpy(data, M68000_regs.d, 0x40);
|
||||
memcpy(data+0x40,&M68000_regs.pc,0x04);
|
||||
#elif defined(EMU_M68K)
|
||||
memcpy(data, PicoM68kCPU.dar,0x40);
|
||||
memcpy(data+0x40,&PicoM68kCPU.pc, 0x04);
|
||||
#endif
|
||||
}
|
108
Pico/Utils.c
Normal file
108
Pico/Utils.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
int PicuAnd=0xf7de;
|
||||
|
||||
// Quick low-quality conversion of 320 to 176:
|
||||
int PicuQuick(unsigned short *dest,unsigned short *src)
|
||||
{
|
||||
unsigned short *end=NULL;
|
||||
|
||||
src+=13; end=src+290;
|
||||
dest++;
|
||||
|
||||
do
|
||||
{
|
||||
*dest++=*src++;
|
||||
*dest++=*src; src+=2;
|
||||
*dest++=*src; src+=2;
|
||||
*dest++=*src++;
|
||||
*dest++=*src; src+=2;
|
||||
*dest++=*src; src+=2;
|
||||
}
|
||||
while (src<end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Shrink the pixels in src/srcLen, to the screen line pointed to by dest/destLen
|
||||
int PicuShrink(unsigned short *dest,int destLen,unsigned short *src,int srcLen)
|
||||
{
|
||||
unsigned short *end=NULL;
|
||||
int bias=0,pa=0,sub=0;
|
||||
|
||||
end=dest+destLen;
|
||||
sub=srcLen-destLen;
|
||||
|
||||
do
|
||||
{
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
*dest++=(unsigned short)pa;
|
||||
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
*dest++=(unsigned short)pa;
|
||||
}
|
||||
while (dest<end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// same thing, only reversed (dest is in pre-decremental mode)
|
||||
int PicuShrinkReverse(unsigned short *dest,int destLen,unsigned short *src,int srcLen)
|
||||
{
|
||||
unsigned short *end=NULL;
|
||||
int bias=0,pa=0,sub=0;
|
||||
|
||||
end=dest-destLen;
|
||||
sub=srcLen-destLen;
|
||||
|
||||
do
|
||||
{
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
*(--dest)=(unsigned short)pa;
|
||||
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
*(--dest)=(unsigned short)pa;
|
||||
}
|
||||
while (dest>end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PicuMerge(unsigned short *dest,int destLen,unsigned short *src,int srcLen)
|
||||
{
|
||||
unsigned short *end=NULL;
|
||||
int bias=0,pa=0,mask=PicuAnd,sub=0;
|
||||
|
||||
end=dest+destLen;
|
||||
sub=srcLen-destLen;
|
||||
|
||||
do
|
||||
{
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
pa&=mask; pa+=(*dest)&mask; pa>>=1;
|
||||
*dest++=(unsigned short)pa;
|
||||
|
||||
pa=*src++; bias-=sub;
|
||||
if (bias<0) { pa+=*src++; pa>>=1; bias+=destLen; }
|
||||
pa&=mask; pa+=(*dest)&mask; pa>>=1;
|
||||
*dest++=(unsigned short)pa;
|
||||
}
|
||||
while (dest<end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
432
Pico/VideoPort.c
Normal file
432
Pico/VideoPort.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "PicoInt.h"
|
||||
|
||||
extern const unsigned char hcounts_32[];
|
||||
extern const unsigned char hcounts_40[];
|
||||
extern const unsigned short vcounts[];
|
||||
extern int rendstatus;
|
||||
|
||||
typedef unsigned short u16;
|
||||
|
||||
|
||||
static __inline void AutoIncrement()
|
||||
{
|
||||
Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);
|
||||
}
|
||||
|
||||
static void VideoWrite(u16 d)
|
||||
{
|
||||
unsigned int a=Pico.video.addr;
|
||||
|
||||
switch (Pico.video.type)
|
||||
{
|
||||
case 1: if(a&1) d=(u16)((d<<8)|(d>>8)); // If address is odd, bytes are swapped (which game needs this?)
|
||||
Pico.vram [(a>>1)&0x7fff]=d;
|
||||
rendstatus|=0x10; break;
|
||||
case 3: Pico.m.dirtyPal = 1;
|
||||
//dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone());
|
||||
Pico.cram [(a>>1)&0x003f]=d; break; // wraps (Desert Strike)
|
||||
case 5: Pico.vsram[(a>>1)&0x003f]=d; break;
|
||||
}
|
||||
|
||||
//dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone());
|
||||
AutoIncrement();
|
||||
}
|
||||
|
||||
static unsigned int VideoRead()
|
||||
{
|
||||
unsigned int a=0,d=0;
|
||||
|
||||
a=Pico.video.addr; a>>=1;
|
||||
|
||||
switch (Pico.video.type)
|
||||
{
|
||||
case 0: d=Pico.vram [a&0x7fff]; break;
|
||||
case 8: d=Pico.cram [a&0x003f]; break;
|
||||
case 4: d=Pico.vsram[a&0x003f]; break;
|
||||
}
|
||||
|
||||
AutoIncrement();
|
||||
return d;
|
||||
}
|
||||
|
||||
// calculate the number of cycles 68k->VDP dma operation would take
|
||||
static int DmaSlowBurn(int len)
|
||||
{
|
||||
// test: Legend of Galahad, Time Killers
|
||||
int burn,maxlen,line=Pico.m.scanline;
|
||||
|
||||
if(line == -1) line=vcounts[SekCyclesDone()>>8];
|
||||
maxlen=(224-line)*18;
|
||||
if(len <= maxlen)
|
||||
burn = len*(((488<<8)/18))>>8;
|
||||
else {
|
||||
burn = maxlen*(((488<<8)/18))>>8;
|
||||
burn += (len-maxlen)*(((488<<8)/180))>>8;
|
||||
}
|
||||
|
||||
return burn;
|
||||
}
|
||||
|
||||
static int GetDmaLength()
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int len=0;
|
||||
// 16-bit words to transfer:
|
||||
len =pvid->reg[0x13];
|
||||
len|=pvid->reg[0x14]<<8;
|
||||
// Charles MacDonald:
|
||||
if(!len) len = 0xffff;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void DmaSlow(int len)
|
||||
{
|
||||
u16 *pd=0, *pdend, *r;
|
||||
unsigned int a=Pico.video.addr, a2, d;
|
||||
unsigned char inc=Pico.video.reg[0xf];
|
||||
unsigned int source, burn;
|
||||
|
||||
source =Pico.video.reg[0x15]<<1;
|
||||
source|=Pico.video.reg[0x16]<<9;
|
||||
source|=Pico.video.reg[0x17]<<17;
|
||||
|
||||
//dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc,
|
||||
// (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone());
|
||||
|
||||
if ((source&0xe00000)==0xe00000) { pd=(u16 *)(Pico.ram+(source&0xfffe)); pdend=(u16 *)(Pico.ram+0x10000); } // Ram
|
||||
else if(source<Pico.romsize) { pd=(u16 *)(Pico.rom+(source&~1)); pdend=(u16 *)(Pico.rom+Pico.romsize); } // Rom
|
||||
else return; // Invalid source address
|
||||
|
||||
// CPU is stopped during DMA, so we burn some cycles to compensate that
|
||||
if((Pico.video.status&8)||!(Pico.video.reg[1]&0x40)) { // vblank?
|
||||
burn = (len*(((488<<8)/167))>>8); // very approximate
|
||||
if(!(Pico.video.status&8)) burn+=burn>>1; // a hack for Legend of Galahad
|
||||
} else burn = DmaSlowBurn(len);
|
||||
SekCyclesBurn(burn);
|
||||
if(!(Pico.video.status&8))
|
||||
SekEndRun(0);
|
||||
//dprintf("DmaSlow burn: %i @ %06x", burn, SekPc);
|
||||
|
||||
switch (Pico.video.type)
|
||||
{
|
||||
case 1: // vram
|
||||
r = Pico.vram;
|
||||
for(; len; len--)
|
||||
{
|
||||
d=*pd++;
|
||||
if(a&1) d=(d<<8)|(d>>8);
|
||||
r[a>>1] = (u16)d; // will drop the upper bits
|
||||
// AutoIncrement
|
||||
a=(u16)(a+inc);
|
||||
// didn't src overlap?
|
||||
if(pd >= pdend) pd-=0x8000; // should be good for RAM, bad for ROM
|
||||
}
|
||||
rendstatus|=0x10;
|
||||
break;
|
||||
|
||||
case 3: // cram
|
||||
//dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc,
|
||||
// (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone());
|
||||
Pico.m.dirtyPal = 1;
|
||||
r = Pico.cram;
|
||||
for(a2=a&0x7f; len; len--)
|
||||
{
|
||||
r[a2>>1] = (u16)*pd++;; // bit 0 is ignored
|
||||
// AutoIncrement
|
||||
a2+=inc;
|
||||
// didn't src overlap?
|
||||
if(pd >= pdend) pd-=0x8000;
|
||||
// good dest?
|
||||
if(a2 >= 0x80) break; // Todds Adventures in Slime World / Andre Agassi tennis
|
||||
}
|
||||
a=(a&0xff00)|a2;
|
||||
break;
|
||||
|
||||
case 5: // vsram[a&0x003f]=d;
|
||||
r = Pico.vsram;
|
||||
for(a2=a&0x7f; len; len--)
|
||||
{
|
||||
r[a2>>1] = (u16)*pd++;
|
||||
// AutoIncrement
|
||||
a2+=inc;
|
||||
// didn't src overlap?
|
||||
if(pd >= pdend) pd-=0x8000;
|
||||
// good dest?
|
||||
if(a2 >= 0x80) break;
|
||||
}
|
||||
a=(a&0xff00)|a2;
|
||||
break;
|
||||
}
|
||||
// remember addr
|
||||
Pico.video.addr=(u16)a;
|
||||
}
|
||||
|
||||
static void DmaCopy(int len)
|
||||
{
|
||||
u16 a=Pico.video.addr;
|
||||
unsigned char *vr = (unsigned char *) Pico.vram;
|
||||
unsigned char *vrs;
|
||||
unsigned char inc=Pico.video.reg[0xf];
|
||||
int source;
|
||||
//dprintf("DmaCopy len %i [%i|%i]", len, Pico.m.scanline, SekCyclesDone());
|
||||
|
||||
source =Pico.video.reg[0x15];
|
||||
source|=Pico.video.reg[0x16]<<8;
|
||||
vrs=vr+source;
|
||||
|
||||
if(source+len > 0x10000) len=0x10000-source; // clip??
|
||||
|
||||
for(;len;len--)
|
||||
{
|
||||
vr[a] = *vrs++;
|
||||
// AutoIncrement
|
||||
a=(u16)(a+inc);
|
||||
}
|
||||
// remember addr
|
||||
Pico.video.addr=a;
|
||||
rendstatus|=0x10;
|
||||
}
|
||||
|
||||
// check: Contra, Megaman
|
||||
// note: this is still inaccurate
|
||||
static void DmaFill(int data)
|
||||
{
|
||||
int len;
|
||||
unsigned short a=Pico.video.addr;
|
||||
unsigned char *vr=(unsigned char *) Pico.vram;
|
||||
unsigned char high = (unsigned char) (data >> 8);
|
||||
unsigned char inc=Pico.video.reg[0xf];
|
||||
|
||||
len=GetDmaLength();
|
||||
//dprintf("DmaFill len %i inc %i [%i|%i]", len, inc, Pico.m.scanline, SekCyclesDone());
|
||||
|
||||
// from Charles MacDonald's genvdp.txt:
|
||||
// Write lower byte to address specified
|
||||
vr[a] = (unsigned char) data;
|
||||
a=(u16)(a+inc);
|
||||
|
||||
if(!inc) len=1;
|
||||
|
||||
for(;len;len--) {
|
||||
// Write upper byte to adjacent address
|
||||
// (here we are byteswapped, so address is already 'adjacent')
|
||||
vr[a] = high;
|
||||
|
||||
// Increment address register
|
||||
a=(u16)(a+inc);
|
||||
}
|
||||
// remember addr
|
||||
Pico.video.addr=a;
|
||||
// update length
|
||||
Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze)
|
||||
|
||||
rendstatus|=0x10;
|
||||
}
|
||||
|
||||
static void CommandDma()
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
int len=0,method=0;
|
||||
|
||||
if ((pvid->reg[1]&0x10)==0) return; // DMA not enabled
|
||||
|
||||
len=GetDmaLength();
|
||||
|
||||
method=pvid->reg[0x17]>>6;
|
||||
if (method< 2) DmaSlow(len); // 68000 to VDP
|
||||
if (method==3) DmaCopy(len); // VRAM Copy
|
||||
}
|
||||
|
||||
static void CommandChange()
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
unsigned int cmd=0,addr=0;
|
||||
|
||||
cmd=pvid->command;
|
||||
|
||||
// Get type of transfer 0xc0000030 (v/c/vsram read/write)
|
||||
pvid->type=(unsigned char)(((cmd>>2)&0xc)|(cmd>>30));
|
||||
|
||||
// Get address 0x3fff0003
|
||||
addr =(cmd>>16)&0x3fff;
|
||||
addr|=(cmd<<14)&0xc000;
|
||||
pvid->addr=(unsigned short)addr;
|
||||
//dprintf("addr set: %04x", addr);
|
||||
|
||||
// Check for dma:
|
||||
if (cmd&0x80) CommandDma();
|
||||
}
|
||||
|
||||
void PicoVideoWrite(unsigned int a,unsigned short d)
|
||||
{
|
||||
struct PicoVideo *pvid=&Pico.video;
|
||||
|
||||
a&=0x1c;
|
||||
|
||||
if (a==0x00) // Data port 0 or 2
|
||||
{
|
||||
if (pvid->pending) CommandChange();
|
||||
pvid->pending=0;
|
||||
|
||||
// If a DMA fill has been set up, do it
|
||||
if ((pvid->command&0x80) && (pvid->reg[1]&0x10) && (pvid->reg[0x17]>>6)==2)
|
||||
{
|
||||
DmaFill(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoWrite(d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (a==0x04) // Control (command) port 4 or 6
|
||||
{
|
||||
//dprintf("vdp cw(%04x), p=%i @ %06x [%i]", d, pvid->pending, SekPc, SekCyclesDone());
|
||||
if(pvid->pending)
|
||||
{
|
||||
// Low word of command:
|
||||
pvid->command&=0xffff0000;
|
||||
pvid->command|=d;
|
||||
pvid->pending=0;
|
||||
CommandChange();
|
||||
} else {
|
||||
if((d&0xc000)==0x8000)
|
||||
{
|
||||
// Register write:
|
||||
int num=(d>>8)&0x1f;
|
||||
//if(num==00) dprintf("hint_onoff: %i->%i [%i|%i] pend=%i @ %06x", (pvid->reg[0]&0x10)>>4, (d&0x10)>>4, Pico.m.scanline, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc);
|
||||
//if(num==01) dprintf("vint_onoff: %i->%i [%i|%i] pend=%i @ %06x", (pvid->reg[1]&0x20)>>5, (d&0x20)>>5, Pico.m.scanline, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc);
|
||||
//if(num==01) dprintf("set_blank: %i @ %06x [%i|%i]", !((d&0x40)>>6), SekPc, Pico.m.scanline, SekCyclesDone());
|
||||
//if(num==05) dprintf("spr_set: %i @ %06x [%i|%i]", (unsigned char)d, SekPc, Pico.m.scanline, SekCyclesDone());
|
||||
//if(num==10) dprintf("hint_set: %i @ %06x [%i|%i]", (unsigned char)d, SekPc, Pico.m.scanline, SekCyclesDone());
|
||||
pvid->reg[num]=(unsigned char)d;
|
||||
#if !(defined(EMU_C68K) && defined(EMU_M68K)) // not debugging Cyclone
|
||||
// update IRQ level (Lemmings, Wiz 'n' Liz intro, ... )
|
||||
// may break if done improperly:
|
||||
// International Superstar Soccer Deluxe (crash), Street Racer (logos), Burning Force (gfx), Fatal Rewind (hang), Sesame Street Counting Cafe
|
||||
if(num < 2) {
|
||||
#ifdef EMU_C68K
|
||||
// hack: make sure we do not touch the irq line if Cyclone is just about to take the IRQ
|
||||
if (PicoCpu.irq <= (PicoCpu.srh&7)) {
|
||||
#endif
|
||||
int lines, pints;
|
||||
lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10);
|
||||
pints = (pvid->pending_ints&lines);
|
||||
if(pints & 0x20) SekInterrupt(6);
|
||||
else if(pints & 0x10) SekInterrupt(4);
|
||||
else SekInterrupt(0);
|
||||
#ifdef EMU_C68K
|
||||
// adjust cycles for Cyclone so it would take the int "in time"
|
||||
if(PicoCpu.irq) {
|
||||
SekEndRun(24);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(num == 5) rendstatus|=1;
|
||||
else if(num == 0xc) Pico.m.dirtyPal = 2; // renderers should update their palettes if sh/hi mode is changed
|
||||
pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)
|
||||
} else {
|
||||
// High word of command:
|
||||
pvid->command&=0x0000ffff;
|
||||
pvid->command|=d<<16;
|
||||
pvid->pending=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int PicoVideoRead(unsigned int a)
|
||||
{
|
||||
unsigned int d=0;
|
||||
|
||||
a&=0x1c;
|
||||
|
||||
if (a==0x00) // data port
|
||||
{
|
||||
d=VideoRead();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (a==0x04) // control port
|
||||
{
|
||||
//dprintf("sr_read @ %06x [%i|%i]", SekPc, Pico.m.scanline, SekCyclesDone());
|
||||
d=Pico.video.status;
|
||||
if(PicoOpt&0x10) d|=0x0020; // sprite collision (Shadow of the Beast)
|
||||
if(Pico.m.rotate++&8) d|=0x0100; else d|=0x0200; // Toggle fifo full empty (who uses that stuff?)
|
||||
if(!(Pico.video.reg[1]&0x40)) d|=0x0008; // set V-Blank if display is disabled
|
||||
if(SekCyclesLeft < 84+4) d|=0x0004; // H-Blank (Sonic3 vs)
|
||||
|
||||
Pico.video.pending=0; // ctrl port reads clear write-pending flag (Charles MacDonald)
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
// H-counter info (based on Generator):
|
||||
// frame:
|
||||
// | <- hblank? -> |
|
||||
// start <416> hint <36> hdisplay <38> end // CPU cycles
|
||||
// |---------...---------|------------|-------------|
|
||||
// 0 B6 E4 FF // 40 cells
|
||||
// 0 93 E8 FF // 32 cells
|
||||
|
||||
// Gens (?) v-render
|
||||
// start <hblank=84> hint hdisplay <404> |
|
||||
// |---------------------|--------------------------|
|
||||
// E4 (hc[0x43]==0) 07 B1 // 40
|
||||
// E8 (hc[0x45]==0) 05 91 // 32
|
||||
|
||||
// check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune
|
||||
if ((a&0x1c)==0x08)
|
||||
{
|
||||
unsigned int hc;
|
||||
|
||||
if(Pico.m.scanline != -1) {
|
||||
int lineCycles=(488-SekCyclesLeft)&0x1ff;
|
||||
d=Pico.m.scanline; // V-Counter
|
||||
|
||||
if(Pico.video.reg[12]&1)
|
||||
hc=hcounts_40[lineCycles];
|
||||
else hc=hcounts_32[lineCycles];
|
||||
|
||||
if(lineCycles > 488-12) d++; // Wheel of Fortune
|
||||
} else {
|
||||
// get approximate V-Counter
|
||||
d=vcounts[SekCyclesDone()>>8];
|
||||
hc = Pico.m.rotate&0xff;
|
||||
}
|
||||
|
||||
if(Pico.m.pal) {
|
||||
if(d >= 0x103) d-=56; // based on Gens
|
||||
} else {
|
||||
if(d >= 0xEB) d-=6;
|
||||
}
|
||||
|
||||
if((Pico.video.reg[12]&6) == 6) {
|
||||
// interlace mode 2 (Combat Cars (UE) [!])
|
||||
d <<= 1;
|
||||
if (d&0xf00) d|= 1;
|
||||
}
|
||||
|
||||
//dprintf("hv: %02x %02x (%i) @ %06x", hc, d, SekCyclesDone(), SekPc);
|
||||
d&=0xff; d<<=8;
|
||||
d|=hc;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
return d;
|
||||
}
|
130
Pico/_cyclone_debug.c
Normal file
130
Pico/_cyclone_debug.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "PicoInt.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
|
||||
static unsigned int pppc, ops=0;
|
||||
extern unsigned int lastread_a, lastread_d[16], lastwrite_cyc_d[16], lastwrite_mus_d[16];
|
||||
extern int lrp_cyc, lrp_mus, lwp_cyc, lwp_mus;
|
||||
unsigned int old_regs[16], old_sr, ppop;
|
||||
|
||||
//static
|
||||
void dumpPCandExit()
|
||||
{
|
||||
char buff[128];
|
||||
int i;
|
||||
|
||||
m68k_disassemble(buff, pppc, M68K_CPU_TYPE_68000);
|
||||
dprintf("PC: %06x: %04x: %s", pppc, ppop, buff);
|
||||
for(i=0; i < 8; i++)
|
||||
dprintf("d%i=%08x, a%i=%08x | d%i=%08x, a%i=%08x", i, PicoCpu.d[i], i, PicoCpu.a[i], i, old_regs[i], i, old_regs[i+8]);
|
||||
dprintf("SR: %04x | %04x (??s? 0iii 000x nzvc)", CycloneGetSr(&PicoCpu), old_sr);
|
||||
dprintf("last_read: %08x @ %06x", lastread_d[--lrp_cyc&15], lastread_a);
|
||||
dprintf("ops done: %i", ops);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int CM_compareRun(int cyc)
|
||||
{
|
||||
char *str;
|
||||
int cyc_done=0, cyc_cyclone, cyc_musashi, err=0;
|
||||
unsigned int i, mu_sr;
|
||||
|
||||
lrp_cyc = lrp_mus = 0;
|
||||
|
||||
while(cyc > cyc_done) {
|
||||
pppc = SekPc;
|
||||
ppop = m68k_read_disassembler_16(pppc);
|
||||
memcpy(old_regs, PicoCpu.d, 4*16);
|
||||
old_sr = CycloneGetSr(&PicoCpu);
|
||||
|
||||
PicoCpu.cycles=1;
|
||||
CycloneRun(&PicoCpu);
|
||||
cyc_cyclone=1-PicoCpu.cycles;
|
||||
cyc_musashi=m68k_execute(1);
|
||||
|
||||
if(cyc_cyclone != cyc_musashi) {
|
||||
dprintf("cycles: %i vs %i", cyc_cyclone, cyc_musashi);
|
||||
err=1;
|
||||
}
|
||||
|
||||
if(lrp_cyc != lrp_mus) {
|
||||
dprintf("lrp: %i vs %i", lrp_cyc&15, lrp_mus&15);
|
||||
err=1;
|
||||
}
|
||||
|
||||
if(lwp_cyc != lwp_mus) {
|
||||
dprintf("lwp: %i vs %i", lwp_cyc&15, lwp_mus&15);
|
||||
err=1;
|
||||
}
|
||||
|
||||
for(i=0; i < 16; i++) {
|
||||
if(lastwrite_cyc_d[i] != lastwrite_mus_d[i]) {
|
||||
dprintf("lastwrite: [%i]= %08x vs %08x", i, lastwrite_cyc_d[i], lastwrite_mus_d[i]);
|
||||
err=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// compare PC
|
||||
if( SekPc != (m68ki_cpu.pc&0xffffff) ) {
|
||||
dprintf("PC: %06x vs %06x", SekPc, m68ki_cpu.pc&0xffffff);
|
||||
err=1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if( SekPc > Pico.romsize || SekPc < 0x200 ) {
|
||||
dprintf("PC out of bounds: %06x", SekPc);
|
||||
err=1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// compare regs
|
||||
for(i=0; i < 16; i++) {
|
||||
if(PicoCpu.d[i] != m68ki_cpu.dar[i]) {
|
||||
str = (i < 8) ? "d" : "a";
|
||||
dprintf("reg: %s%i: %08x vs %08x", str, i&7, PicoCpu.d[i], m68ki_cpu.dar[i]);
|
||||
err=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SR
|
||||
if((CycloneGetSr(&PicoCpu)) != (mu_sr = m68k_get_reg(NULL, M68K_REG_SR))) {
|
||||
dprintf("SR: %04x vs %04x (??s? 0iii 000x nzvc)", CycloneGetSr(&PicoCpu), mu_sr);
|
||||
err=1;
|
||||
}
|
||||
|
||||
// IRQl
|
||||
if(PicoCpu.irq != (m68ki_cpu.int_level>>8)) {
|
||||
dprintf("IRQ: %i vs %i", PicoCpu.irq, (m68ki_cpu.int_level>>8));
|
||||
err=1;
|
||||
}
|
||||
|
||||
// OSP/USP
|
||||
if(PicoCpu.osp != m68ki_cpu.sp[((mu_sr>>11)&4)^4]) {
|
||||
dprintf("OSP: %06x vs %06x", PicoCpu.osp, m68ki_cpu.sp[0]);
|
||||
err=1;
|
||||
}
|
||||
|
||||
// stopped
|
||||
if((PicoCpu.stopped && !m68ki_cpu.stopped) || (!PicoCpu.stopped && m68ki_cpu.stopped)) {
|
||||
dprintf("stopped: %i vs %i", PicoCpu.stopped, m68ki_cpu.stopped);
|
||||
err=1;
|
||||
}
|
||||
|
||||
if(err) dumpPCandExit();
|
||||
|
||||
#if 0
|
||||
m68k_set_reg(M68K_REG_SR, ((mu_sr-1)&~0x2000)|(mu_sr&0x2000)); // broken
|
||||
CycloneSetSr(&PicoCpu, ((mu_sr-1)&~0x2000)|(mu_sr&0x2000));
|
||||
PicoCpu.stopped = m68ki_cpu.stopped = 0;
|
||||
if(SekPc > 0x400 && (PicoCpu.a[7] < 0xff0000 || PicoCpu.a[7] > 0xffffff))
|
||||
PicoCpu.a[7] = m68ki_cpu.dar[15] = 0xff8000;
|
||||
#endif
|
||||
|
||||
cyc_done += cyc_cyclone;
|
||||
ops++;
|
||||
}
|
||||
|
||||
return cyc_done;
|
||||
}
|
658
Pico/cd/LC89510.c
Normal file
658
Pico/cd/LC89510.c
Normal file
|
@ -0,0 +1,658 @@
|
|||
#if 0
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "misc.h"
|
||||
#include "lc89510.h"
|
||||
#include "cd_aspi.h"
|
||||
#include "Star_68k.h"
|
||||
#include "mem_S68k.h"
|
||||
#include "pcm.h"
|
||||
#endif
|
||||
|
||||
#include "../PicoInt.h"
|
||||
|
||||
#define cdprintf printf
|
||||
//#define cdprintf(x...)
|
||||
|
||||
|
||||
#define CDC_DMA_SPEED 256
|
||||
|
||||
int CDC_Decode_Reg_Read;
|
||||
static int Status_CDC; // internal status
|
||||
|
||||
|
||||
static void CDD_Reset(void)
|
||||
{
|
||||
// Reseting CDD
|
||||
|
||||
memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control
|
||||
Pico_mcd->cdd.Status = 0;
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
// clear receive status and transfer command
|
||||
memset(Pico_mcd->s68k_regs+0x38, 0, 20);
|
||||
Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum
|
||||
}
|
||||
|
||||
|
||||
static void CDC_Reset(void)
|
||||
{
|
||||
// Reseting CDC
|
||||
|
||||
memset(Pico_mcd->cdc.Buffer, 0, (16 * 1024 * 2) + 2352);
|
||||
|
||||
CDC_Update_Header();
|
||||
|
||||
Pico_mcd->cdc.COMIN = 0;
|
||||
Pico_mcd->cdc.IFSTAT = 0xFF;
|
||||
Pico_mcd->cdc.DAC.N = 0;
|
||||
Pico_mcd->cdc.DBC.N = 0;
|
||||
Pico_mcd->cdc.HEAD.N = 0x01000000;
|
||||
Pico_mcd->cdc.PT.N = 0;
|
||||
Pico_mcd->cdc.WA.N = 2352 * 2;
|
||||
Pico_mcd->cdc.STAT.N = 0x00000080;
|
||||
Pico_mcd->cdc.SBOUT = 0;
|
||||
Pico_mcd->cdc.IFCTRL = 0;
|
||||
Pico_mcd->cdc.CTRL.N = 0;
|
||||
|
||||
CDC_Decode_Reg_Read = 0;
|
||||
Status_CDC = 0;
|
||||
}
|
||||
|
||||
|
||||
void LC89510_Reset(void)
|
||||
{
|
||||
CDD_Reset();
|
||||
CDC_Reset();
|
||||
|
||||
Pico_mcd->cdc.Host_Data = 0;
|
||||
Pico_mcd->cdc.DMA_Adr = 0;
|
||||
Pico_mcd->cdc.Stop_Watch = 0;
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
void Update_CDC_TRansfer(void)
|
||||
{
|
||||
unsigned int i, dep, lenght, add_dest;
|
||||
unsigned char *dest;
|
||||
|
||||
if ((Status_CDC & 0x08) == 0) return;
|
||||
|
||||
switch(Pico_mcd->s68k_regs[4] & 7)
|
||||
{
|
||||
case 0x0200: // MAIN CPU
|
||||
case 0x0300: // SUB CPU
|
||||
Pico_mcd->s68k_regs[4] |= 0x40; // Data ready in host port
|
||||
return;
|
||||
|
||||
case 0x0400: // PCM RAM
|
||||
dest = (unsigned char *) Ram_PCM;
|
||||
dep = ((Pico_mcd->cdc.DMA_Adr & 0x03FF) << 2) + PCM_Chip.Bank;
|
||||
add_dest = 2;
|
||||
break;
|
||||
|
||||
case 0x0500: // PRG RAM
|
||||
dest = (unsigned char *) Ram_Prg;
|
||||
dep = (Pico_mcd->cdc.DMA_Adr & 0xFFFF) << 3;
|
||||
add_dest = 2;
|
||||
// cdprintf("DMA transfer PRG RAM : adr = %.8X ", dep);
|
||||
break;
|
||||
|
||||
case 0x0700: // WORD RAM
|
||||
if (Ram_Word_State >= 2)
|
||||
{
|
||||
dest = (unsigned char *) Ram_Word_1M;
|
||||
add_dest = 2;
|
||||
if (Ram_Word_State & 1) dep = ((Pico_mcd->cdc.DMA_Adr & 0x3FFF) << 3);
|
||||
else dep = ((Pico_mcd->cdc.DMA_Adr & 0x3FFF) << 3) + 0x20000;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = (unsigned char *) Ram_Word_2M;
|
||||
dep = ((Pico_mcd->cdc.DMA_Adr & 0x7FFF) << 3);
|
||||
add_dest = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (Pico_mcd->cdc.DBC.N <= (CDC_DMA_SPEED * 2))
|
||||
{
|
||||
lenght = (Pico_mcd->cdc.DBC.N + 1) >> 1;
|
||||
Status_CDC &= ~0x08; // Last transfer
|
||||
Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer
|
||||
Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready
|
||||
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
|
||||
|
||||
if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Trasnfer End Interrupt Enable ?
|
||||
{
|
||||
Pico_mcd->cdc.IFSTAT &= ~0x40;
|
||||
|
||||
if (Int_Mask_S68K & 0x20) sub68k_interrupt(5, -1);
|
||||
|
||||
cdprintf("CDC - DTE interrupt\n");
|
||||
}
|
||||
}
|
||||
else lenght = CDC_DMA_SPEED;
|
||||
|
||||
// cdprintf("DMA lenght = %.4X\n", lenght);
|
||||
|
||||
|
||||
if ((Pico_mcd->s68k_regs[4] & 7) == 4) // PCM DMA
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov ecx, lenght
|
||||
mov edi, dest
|
||||
lea esi, Pico_mcd->cdc.Buffer
|
||||
add edi, dep
|
||||
add esi, Pico_mcd->cdc.DAC.N
|
||||
mov ebx, add_dest
|
||||
|
||||
Loop_DMA_PCM:
|
||||
mov ax, [esi]
|
||||
add esi, 2
|
||||
mov [edi], ax
|
||||
add edi, ebx
|
||||
dec ecx
|
||||
jnz Loop_DMA_PCM
|
||||
}
|
||||
|
||||
lenght <<= 1;
|
||||
Pico_mcd->cdc.DMA_Adr += lenght >> 2;
|
||||
}
|
||||
else // OTHER DMA
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov ecx, lenght
|
||||
mov edi, dest
|
||||
lea esi, Pico_mcd->cdc.Buffer
|
||||
add edi, dep
|
||||
add esi, Pico_mcd->cdc.DAC.N
|
||||
mov ebx, add_dest
|
||||
|
||||
Loop_DMA:
|
||||
mov ax, [esi]
|
||||
add esi, 2
|
||||
rol ax, 8
|
||||
mov [edi], ax
|
||||
add edi, ebx
|
||||
dec ecx
|
||||
jnz Loop_DMA
|
||||
}
|
||||
|
||||
lenght <<= 1;
|
||||
Pico_mcd->cdc.DMA_Adr += lenght >> 3;
|
||||
}
|
||||
|
||||
Pico_mcd->cdc.DAC.N = (Pico_mcd->cdc.DAC.N + lenght) & 0xFFFF;
|
||||
if (Status_CDC & 0x08) Pico_mcd->cdc.DBC.N -= lenght;
|
||||
else Pico_mcd->cdc.DBC.N = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
unsigned short Read_CDC_Host(int is_sub)
|
||||
{
|
||||
int addr;
|
||||
|
||||
if (!(Status_CDC & 0x08))
|
||||
{
|
||||
// Transfer data disabled
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((is_sub && (Pico_mcd->s68k_regs[4] & 7) != 3) ||
|
||||
(!is_sub && (Pico_mcd->s68k_regs[4] & 7) != 2))
|
||||
{
|
||||
// Wrong setting
|
||||
return 0;
|
||||
}
|
||||
|
||||
Pico_mcd->cdc.DBC.N -= 2;
|
||||
|
||||
if (Pico_mcd->cdc.DBC.N <= 0)
|
||||
{
|
||||
Pico_mcd->cdc.DBC.N = 0;
|
||||
Status_CDC &= ~0x08; // Last transfer
|
||||
Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer
|
||||
Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready
|
||||
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
|
||||
|
||||
if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Transfer End Interrupt Enable ?
|
||||
{
|
||||
Pico_mcd->cdc.IFSTAT &= ~0x40;
|
||||
|
||||
if (Pico_mcd->s68k_regs[0x33]&(1<<5)) {
|
||||
dprintf("m68k: s68k irq 5");
|
||||
SekInterruptS68k(5);
|
||||
}
|
||||
|
||||
cdprintf("CDC - DTE interrupt\n");
|
||||
}
|
||||
}
|
||||
|
||||
addr = Pico_mcd->cdc.DAC.N;
|
||||
Pico_mcd->cdc.DAC.N += 2;
|
||||
return (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1];
|
||||
|
||||
#if 0
|
||||
__asm
|
||||
{
|
||||
mov esi, Pico_mcd->cdc.DAC.N
|
||||
lea ebx, Pico_mcd->cdc.Buffer
|
||||
// and esi, 0x3FFF
|
||||
mov ax, [ebx + esi]
|
||||
add esi, 2
|
||||
rol ax, 8
|
||||
mov Pico_mcd->cdc.DAC.N, esi
|
||||
mov val, ax
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CDC_Update_Header(void)
|
||||
{
|
||||
if (Pico_mcd->cdc.CTRL.B.B1 & 0x01) // Sub-Header wanted ?
|
||||
{
|
||||
Pico_mcd->cdc.HEAD.B.B0 = 0;
|
||||
Pico_mcd->cdc.HEAD.B.B1 = 0;
|
||||
Pico_mcd->cdc.HEAD.B.B2 = 0;
|
||||
Pico_mcd->cdc.HEAD.B.B3 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
|
||||
|
||||
Pico_mcd->cdc.HEAD.B.B0 = INT_TO_BCDB(MSF.M);
|
||||
Pico_mcd->cdc.HEAD.B.B1 = INT_TO_BCDB(MSF.S);
|
||||
Pico_mcd->cdc.HEAD.B.B2 = INT_TO_BCDB(MSF.F);
|
||||
Pico_mcd->cdc.HEAD.B.B3 = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char CDC_Read_Reg(void)
|
||||
{
|
||||
unsigned char ret;
|
||||
|
||||
cdprintf("CDC read reg %.2d = ", Pico_mcd->s68k_regs[5] & 0xF);
|
||||
|
||||
switch(Pico_mcd->s68k_regs[5] & 0xF)
|
||||
{
|
||||
case 0x0: // COMIN
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.COMIN);
|
||||
|
||||
Pico_mcd->s68k_regs[5] = 0x1;
|
||||
return Pico_mcd->cdc.COMIN;
|
||||
|
||||
case 0x1: // IFSTAT
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.IFSTAT);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 1); // Reg 1 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x2;
|
||||
return Pico_mcd->cdc.IFSTAT;
|
||||
|
||||
case 0x2: // DBCL
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.DBC.B.L);
|
||||
|
||||
Pico_mcd->s68k_regs[5] = 0x3;
|
||||
return Pico_mcd->cdc.DBC.B.L;
|
||||
|
||||
case 0x3: // DBCH
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.DBC.B.H);
|
||||
|
||||
Pico_mcd->s68k_regs[5] = 0x4;
|
||||
return Pico_mcd->cdc.DBC.B.H;
|
||||
|
||||
case 0x4: // HEAD0
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B0);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 4); // Reg 4 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x5;
|
||||
return Pico_mcd->cdc.HEAD.B.B0;
|
||||
|
||||
case 0x5: // HEAD1
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B1);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 5); // Reg 5 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x6;
|
||||
return Pico_mcd->cdc.HEAD.B.B1;
|
||||
|
||||
case 0x6: // HEAD2
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B2);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 6); // Reg 6 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x7;
|
||||
return Pico_mcd->cdc.HEAD.B.B2;
|
||||
|
||||
case 0x7: // HEAD3
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.HEAD.B.B3);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 7); // Reg 7 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x8;
|
||||
return Pico_mcd->cdc.HEAD.B.B3;
|
||||
|
||||
case 0x8: // PTL
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.PT.B.L);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 8); // Reg 8 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0x9;
|
||||
return Pico_mcd->cdc.PT.B.L;
|
||||
|
||||
case 0x9: // PTH
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.PT.B.H);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 9); // Reg 9 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0xA;
|
||||
return Pico_mcd->cdc.PT.B.H;
|
||||
|
||||
case 0xA: // WAL
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.WA.B.L);
|
||||
|
||||
Pico_mcd->s68k_regs[5] = 0xB;
|
||||
return Pico_mcd->cdc.WA.B.L;
|
||||
|
||||
case 0xB: // WAH
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.WA.B.H);
|
||||
|
||||
Pico_mcd->s68k_regs[5] = 0xC;
|
||||
return Pico_mcd->cdc.WA.B.H;
|
||||
|
||||
case 0xC: // STAT0
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B0);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 12); // Reg 12 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0xD;
|
||||
return Pico_mcd->cdc.STAT.B.B0;
|
||||
|
||||
case 0xD: // STAT1
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B1);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 13); // Reg 13 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0xE;
|
||||
return Pico_mcd->cdc.STAT.B.B1;
|
||||
|
||||
case 0xE: // STAT2
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B2);
|
||||
|
||||
CDC_Decode_Reg_Read |= (1 << 14); // Reg 14 (decoding)
|
||||
Pico_mcd->s68k_regs[5] = 0xF;
|
||||
return Pico_mcd->cdc.STAT.B.B2;
|
||||
|
||||
case 0xF: // STAT3
|
||||
cdprintf("%.2X\n", Pico_mcd->cdc.STAT.B.B3);
|
||||
|
||||
ret = Pico_mcd->cdc.STAT.B.B3;
|
||||
Pico_mcd->cdc.IFSTAT |= 0x20; // decoding interrupt flag cleared
|
||||
if ((Pico_mcd->cdc.CTRL.B.B0 & 0x80) && (Pico_mcd->cdc.IFCTRL & 0x20))
|
||||
{
|
||||
if ((CDC_Decode_Reg_Read & 0x73F2) == 0x73F2)
|
||||
Pico_mcd->cdc.STAT.B.B3 = 0x80;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDC_Write_Reg(unsigned char Data)
|
||||
{
|
||||
cdprintf("CDC write reg%d = %.2X\n", Pico_mcd->s68k_regs[5] & 0xF, Data);
|
||||
|
||||
switch (Pico_mcd->s68k_regs[5] & 0xF)
|
||||
{
|
||||
case 0x0: // SBOUT
|
||||
Pico_mcd->s68k_regs[5] = 0x1;
|
||||
Pico_mcd->cdc.SBOUT = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x1: // IFCTRL
|
||||
Pico_mcd->s68k_regs[5] = 0x2;
|
||||
Pico_mcd->cdc.IFCTRL = Data;
|
||||
|
||||
if ((Pico_mcd->cdc.IFCTRL & 0x02) == 0) // Stop data transfer
|
||||
{
|
||||
Pico_mcd->cdc.DBC.N = 0;
|
||||
Status_CDC &= ~0x08;
|
||||
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2: // DBCL
|
||||
Pico_mcd->s68k_regs[5] = 0x3;
|
||||
Pico_mcd->cdc.DBC.B.L = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x3: // DBCH
|
||||
Pico_mcd->s68k_regs[5] = 0x4;
|
||||
Pico_mcd->cdc.DBC.B.H = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x4: // DACL
|
||||
Pico_mcd->s68k_regs[5] = 0x5;
|
||||
Pico_mcd->cdc.DAC.B.L = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x5: // DACH
|
||||
Pico_mcd->s68k_regs[5] = 0x6;
|
||||
Pico_mcd->cdc.DAC.B.H = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x6: // DTTRG
|
||||
if (Pico_mcd->cdc.IFCTRL & 0x02) // Data transfer enable ?
|
||||
{
|
||||
Pico_mcd->cdc.IFSTAT &= ~0x08; // Data transfer in progress
|
||||
Status_CDC |= 0x08; // Data transfer in progress
|
||||
Pico_mcd->s68k_regs[4] &= 0x7F; // A data transfer start
|
||||
|
||||
cdprintf("\n************** Starting Data Transfer ***********\n");
|
||||
cdprintf("RS0 = %.4X DAC = %.4X DBC = %.4X DMA adr = %.4X\n\n", Pico_mcd->s68k_regs[4]<<8,
|
||||
Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N, Pico_mcd->cdc.DMA_Adr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7: // DTACK
|
||||
Pico_mcd->cdc.IFSTAT |= 0x40; // end data transfer interrupt flag cleared
|
||||
break;
|
||||
|
||||
case 0x8: // WAL
|
||||
Pico_mcd->s68k_regs[5] = 0x9;
|
||||
Pico_mcd->cdc.WA.B.L = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0x9: // WAH
|
||||
Pico_mcd->s68k_regs[5] = 0xA;
|
||||
Pico_mcd->cdc.WA.B.H = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0xA: // CTRL0
|
||||
Pico_mcd->s68k_regs[5] = 0xB;
|
||||
Pico_mcd->cdc.CTRL.B.B0 = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0xB: // CTRL1
|
||||
Pico_mcd->s68k_regs[5] = 0xC;
|
||||
Pico_mcd->cdc.CTRL.B.B1 = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0xC: // PTL
|
||||
Pico_mcd->s68k_regs[5] = 0xD;
|
||||
Pico_mcd->cdc.PT.B.L = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0xD: // PTH
|
||||
Pico_mcd->s68k_regs[5] = 0xE;
|
||||
Pico_mcd->cdc.PT.B.H = Data;
|
||||
|
||||
break;
|
||||
|
||||
case 0xE: // CTRL2
|
||||
Pico_mcd->cdc.CTRL.B.B2 = Data;
|
||||
break;
|
||||
|
||||
case 0xF: // RESET
|
||||
CDC_Reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int bswapwrite(int a, unsigned short d)
|
||||
{
|
||||
*(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);
|
||||
return d + (d >> 8);
|
||||
}
|
||||
|
||||
void CDD_Export_Status(void)
|
||||
{
|
||||
unsigned int csum;
|
||||
|
||||
csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);
|
||||
csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);
|
||||
csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);
|
||||
csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);
|
||||
Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;
|
||||
csum += Pico_mcd->cdd.Ext;
|
||||
Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;
|
||||
|
||||
Pico_mcd->s68k_regs[0x36] &= 3; // CDD.Control
|
||||
|
||||
if (Pico_mcd->s68k_regs[0x33] & (1<<4))
|
||||
{
|
||||
dprintf("cdd export irq 4");
|
||||
SekInterruptS68k(4);
|
||||
}
|
||||
|
||||
cdprintf("CDD exported status\n");
|
||||
cdprintf("Status =%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X\n",
|
||||
(Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],
|
||||
(Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],
|
||||
(Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],
|
||||
(Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],
|
||||
(Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);
|
||||
}
|
||||
|
||||
|
||||
void CDD_Import_Command(void)
|
||||
{
|
||||
cdprintf("CDD importing command\n");
|
||||
cdprintf("Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X\n",
|
||||
(Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],
|
||||
(Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],
|
||||
(Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],
|
||||
(Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],
|
||||
(Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);
|
||||
|
||||
switch (Pico_mcd->s68k_regs[0x38+10+0])
|
||||
{
|
||||
case 0x0: // STATUS (?)
|
||||
Get_Status_CDD_c0();
|
||||
break;
|
||||
|
||||
case 0x1: // STOP ALL (?)
|
||||
Stop_CDD_c1();
|
||||
break;
|
||||
|
||||
case 0x2: // GET TOC INFORMATIONS
|
||||
switch(Pico_mcd->s68k_regs[0x38+10+3])
|
||||
{
|
||||
case 0x0: // get current position (MSF format)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);
|
||||
Get_Pos_CDD_c20();
|
||||
break;
|
||||
|
||||
case 0x1: // get elapsed time of current track played/scanned (relative MSF format)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;
|
||||
Get_Track_Pos_CDD_c21();
|
||||
break;
|
||||
|
||||
case 0x2: // get current track in RS2-RS3
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2;
|
||||
Get_Current_Track_CDD_c22();
|
||||
break;
|
||||
|
||||
case 0x3: // get total lenght (MSF format)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;
|
||||
Get_Total_Lenght_CDD_c23();
|
||||
break;
|
||||
|
||||
case 0x4: // first & last track number
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;
|
||||
Get_First_Last_Track_CDD_c24();
|
||||
break;
|
||||
|
||||
case 0x5: // get track addresse (MSF format)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;
|
||||
Get_Track_Adr_CDD_c25();
|
||||
break;
|
||||
|
||||
default : // invalid, then we return status
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;
|
||||
Get_Status_CDD_c0();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3: // READ
|
||||
Play_CDD_c3();
|
||||
break;
|
||||
|
||||
case 0x4: // SEEK
|
||||
Seek_CDD_c4();
|
||||
break;
|
||||
|
||||
case 0x6: // PAUSE/STOP
|
||||
Pause_CDD_c6();
|
||||
break;
|
||||
|
||||
case 0x7: // RESUME
|
||||
Resume_CDD_c7();
|
||||
break;
|
||||
|
||||
case 0x8: // FAST FOWARD
|
||||
Fast_Foward_CDD_c8();
|
||||
break;
|
||||
|
||||
case 0x9: // FAST REWIND
|
||||
Fast_Rewind_CDD_c9();
|
||||
break;
|
||||
|
||||
case 0xA: // RECOVER INITIAL STATE (?)
|
||||
CDD_cA();
|
||||
break;
|
||||
|
||||
case 0xC: // CLOSE TRAY
|
||||
Close_Tray_CDD_cC();
|
||||
break;
|
||||
|
||||
case 0xD: // OPEN TRAY
|
||||
Open_Tray_CDD_cD();
|
||||
break;
|
||||
|
||||
default: // UNKNOWN
|
||||
CDD_Def();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
130
Pico/cd/LC89510.h
Normal file
130
Pico/cd/LC89510.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
#ifndef _LC89510_H
|
||||
#define _LC89510_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int Host_Data;
|
||||
unsigned int DMA_Adr;
|
||||
unsigned int Stop_Watch;
|
||||
unsigned int COMIN;
|
||||
unsigned int IFSTAT;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char L;
|
||||
unsigned char H;
|
||||
unsigned short unused;
|
||||
} B;
|
||||
int N;
|
||||
} DBC;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char L;
|
||||
unsigned char H;
|
||||
unsigned short unused;
|
||||
} B;
|
||||
int N;
|
||||
} DAC;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char B0;
|
||||
unsigned char B1;
|
||||
unsigned char B2;
|
||||
unsigned char B3;
|
||||
} B;
|
||||
unsigned int N;
|
||||
} HEAD;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char L;
|
||||
unsigned char H;
|
||||
unsigned short unused;
|
||||
} B;
|
||||
int N;
|
||||
} PT;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char L;
|
||||
unsigned char H;
|
||||
unsigned short unused;
|
||||
} B;
|
||||
int N;
|
||||
} WA;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char B0;
|
||||
unsigned char B1;
|
||||
unsigned char B2;
|
||||
unsigned char B3;
|
||||
} B;
|
||||
unsigned int N;
|
||||
} STAT;
|
||||
unsigned int SBOUT;
|
||||
unsigned int IFCTRL;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char B0;
|
||||
unsigned char B1;
|
||||
unsigned char B2;
|
||||
unsigned char B3;
|
||||
} B;
|
||||
unsigned int N;
|
||||
} CTRL;
|
||||
unsigned char Buffer[(32 * 1024 * 2) + 2352];
|
||||
} CDC;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// unsigned short Fader; // 34
|
||||
// unsigned short Control; // 36
|
||||
// unsigned short Cur_Comm;// unused
|
||||
|
||||
// "Receive status"
|
||||
unsigned short Status;
|
||||
unsigned short Minute;
|
||||
unsigned short Seconde;
|
||||
unsigned short Frame;
|
||||
unsigned char Ext;
|
||||
} CDD;
|
||||
|
||||
|
||||
extern int CDC_Decode_Reg_Read;
|
||||
|
||||
|
||||
void LC89510_Reset(void);
|
||||
unsigned short Read_CDC_Host(int is_sub);
|
||||
void Update_CDC_TRansfer(void);
|
||||
void CDC_Update_Header(void);
|
||||
|
||||
unsigned char CDC_Read_Reg(void);
|
||||
void CDC_Write_Reg(unsigned char Data);
|
||||
|
||||
void CDD_Export_Status(void);
|
||||
void CDD_Import_Command(void);
|
||||
|
||||
unsigned char SCD_Read_Byte(unsigned int Adr);
|
||||
unsigned short SCD_Read_Word(unsigned int Adr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
788
Pico/cd/Memory.c
Normal file
788
Pico/cd/Memory.c
Normal file
|
@ -0,0 +1,788 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
// A68K no longer supported here
|
||||
|
||||
//#define __debug_io
|
||||
|
||||
#include "../PicoInt.h"
|
||||
|
||||
#include "../sound/sound.h"
|
||||
#include "../sound/ym2612.h"
|
||||
#include "../sound/sn76496.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
//#define __debug_io
|
||||
//#define __debug_io2
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
extern m68ki_cpu_core m68ki_cpu;
|
||||
|
||||
extern int counter75hz;
|
||||
|
||||
|
||||
static u32 m68k_reg_read16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
a &= 0x3e;
|
||||
dprintf("m68k_regs r%2i: [%02x] @%06x", realsize&~1, a+(realsize&1), SekPc);
|
||||
|
||||
switch (a) {
|
||||
case 2:
|
||||
d = (Pico_mcd->m68k_regs[a]<<8) | Pico_mcd->m68k_regs[a+1] | 1; // for now 2M to m68k
|
||||
goto end;
|
||||
case 8:
|
||||
dprintf("m68k host data read");
|
||||
d = Read_CDC_Host(0);
|
||||
goto end;
|
||||
case 0xC:
|
||||
dprintf("m68k stopwatch read");
|
||||
break;
|
||||
}
|
||||
|
||||
if (a < 0xE) {
|
||||
d = (Pico_mcd->m68k_regs[a]<<8) | Pico_mcd->m68k_regs[a+1];
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (a < 0x30) {
|
||||
// comm flag/cmd/status (0xE-0x2F)
|
||||
d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("m68k_regs invalid read @ %02x", a);
|
||||
|
||||
end:
|
||||
|
||||
dprintf("ret = %04x", d);
|
||||
return d;
|
||||
}
|
||||
|
||||
static void m68k_reg_write8(u32 a, u32 d, int realsize)
|
||||
{
|
||||
a &= 0x3f;
|
||||
dprintf("m68k_regs w%2i: [%02x] %02x @%06x", realsize, a, d, SekPc);
|
||||
|
||||
switch (a) {
|
||||
case 0:
|
||||
if ((d&1) && (Pico_mcd->s68k_regs[0x33]&(1<<2))) { dprintf("m68k: s68k irq 2"); SekInterruptS68k(2); }
|
||||
break;
|
||||
case 1:
|
||||
if (!(d&1)) PicoMCD |= 2; // reset pending, needed to be sure we fetch the right vectors on reset
|
||||
if ( (Pico_mcd->m68k_regs[1]&1) != (d&1)) dprintf("m68k: s68k reset %i", !(d&1));
|
||||
if ( (Pico_mcd->m68k_regs[1]&2) != (d&2)) dprintf("m68k: s68k brq %i", (d&2)>>1);
|
||||
if (/*!(Pico_mcd->m68k_regs[1]&1) &&*/ (PicoMCD&2) && (d&3)==1) {
|
||||
SekResetS68k(); // S68k comes out of RESET or BRQ state
|
||||
PicoMCD&=~2;
|
||||
dprintf("m68k: resetting s68k");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ((Pico_mcd->m68k_regs[3]>>6) != ((d>>6)&3))
|
||||
dprintf("m68k: prg bank: %i -> %i", (Pico_mcd->m68k_regs[a]>>6), ((d>>6)&3));
|
||||
if ((Pico_mcd->m68k_regs[3]&4) != (d&4)) dprintf("m68k: ram mode %i mbit", (d&4) ? 1 : 2);
|
||||
if ((Pico_mcd->m68k_regs[3]&2) != (d&2)) dprintf("m68k: %s", (d&4) ? ((d&2) ? "word swap req" : "noop?") :
|
||||
((d&2) ? "word ram to s68k" : "word ram to m68k"));
|
||||
break;
|
||||
case 0xe:
|
||||
dprintf("m68k: comm flag: %02x", d);
|
||||
|
||||
dprintf("s68k @ %06x", SekPcS68k);
|
||||
|
||||
Pico_mcd->s68k_regs[0xe] = d;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((a&0xff) == 0x10) {
|
||||
Pico_mcd->s68k_regs[a] = d;
|
||||
}
|
||||
|
||||
if (a >= 0x20 || (a >= 0xa && a <= 0xd) || a == 0x0f)
|
||||
dprintf("m68k: invalid write?");
|
||||
|
||||
if (a < 0x10)
|
||||
Pico_mcd->m68k_regs[a] = (u8) d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u32 s68k_reg_read16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
a &= 0x1fe;
|
||||
|
||||
dprintf("s68k_regs r%2i: [%02x] @ %06x", realsize&~1, a+(realsize&1), SekPcS68k);
|
||||
|
||||
switch (a) {
|
||||
case 0:
|
||||
d = 1; goto end; // ver = 0, not in reset state
|
||||
case 6:
|
||||
d = CDC_Read_Reg();
|
||||
goto end;
|
||||
case 8:
|
||||
dprintf("s68k host data read");
|
||||
d = Read_CDC_Host(1);
|
||||
goto end;
|
||||
case 0xC:
|
||||
dprintf("s68k stopwatch read");
|
||||
break;
|
||||
case 0x34: // fader
|
||||
d = 0; // no busy bit
|
||||
goto end;
|
||||
}
|
||||
|
||||
d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];
|
||||
|
||||
end:
|
||||
|
||||
dprintf("ret = %04x", d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void s68k_reg_write8(u32 a, u32 d, int realsize)
|
||||
{
|
||||
a &= 0x1ff;
|
||||
dprintf("s68k_regs w%2i: [%02x] %02x @ %06x", realsize, a, d, SekPcS68k);
|
||||
|
||||
// TODO: review against Gens
|
||||
switch (a) {
|
||||
case 4:
|
||||
dprintf("s68k CDC dest: %x", d&7);
|
||||
Pico_mcd->s68k_regs[4] = (Pico_mcd->s68k_regs[4]&0xC0) | (d&7); // CDC mode
|
||||
return;
|
||||
case 5:
|
||||
dprintf("s68k CDC reg addr: %x", d&0xf);
|
||||
break;
|
||||
case 7:
|
||||
CDC_Write_Reg(d);
|
||||
return;
|
||||
case 0xa:
|
||||
dprintf("s68k set CDC dma addr");
|
||||
break;
|
||||
case 0x33: // IRQ mask
|
||||
dprintf("s68k irq mask: %02x", d);
|
||||
if ((d&(1<<4)) && (Pico_mcd->s68k_regs[0x37]&4) && !(Pico_mcd->s68k_regs[0x33]&(1<<4))) {
|
||||
CDD_Export_Status();
|
||||
// counter75hz = 0; // ???
|
||||
}
|
||||
break;
|
||||
case 0x34: // fader
|
||||
Pico_mcd->s68k_regs[a] = (u8) d & 0x7f;
|
||||
return;
|
||||
case 0x37:
|
||||
if ((d&4) && !(Pico_mcd->s68k_regs[0x37]&4)) {
|
||||
CDD_Export_Status();
|
||||
// counter75hz = 0; // ???
|
||||
}
|
||||
break;
|
||||
case 0x4b:
|
||||
Pico_mcd->s68k_regs[a] = (u8) d;
|
||||
CDD_Import_Command();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a&0x1f0) == 0x10 || a == 0x0e || (a >= 0x38 && a < 0x42))
|
||||
{
|
||||
dprintf("m68k: invalid write @ %02x?", a);
|
||||
return;
|
||||
}
|
||||
|
||||
Pico_mcd->s68k_regs[a] = (u8) d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int PadRead(int i)
|
||||
{
|
||||
int pad=0,value=0,TH;
|
||||
pad=~PicoPad[i]; // Get inverse of pad MXYZ SACB RLDU
|
||||
TH=Pico.ioports[i+1]&0x40;
|
||||
|
||||
if(PicoOpt & 0x20) { // 6 button gamepad enabled
|
||||
int phase = Pico.m.padTHPhase[i];
|
||||
|
||||
if(phase == 2 && !TH) {
|
||||
value=(pad&0xc0)>>2; // ?0SA 0000
|
||||
goto end;
|
||||
} else if(phase == 3 && TH) {
|
||||
value=(pad&0x30)|((pad>>8)&0xf); // ?1CB MXYZ
|
||||
goto end;
|
||||
} else if(phase == 3 && !TH) {
|
||||
value=((pad&0xc0)>>2)|0x0f; // ?0SA 1111
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if(TH) value=(pad&0x3f); // ?1CB RLDU
|
||||
else value=((pad&0xc0)>>2)|(pad&3); // ?0SA 00DU
|
||||
|
||||
end:
|
||||
|
||||
// orr the bits, which are set as output
|
||||
value |= Pico.ioports[i+1]&Pico.ioports[i+4];
|
||||
|
||||
return value; // will mirror later
|
||||
}
|
||||
|
||||
static u8 z80Read8(u32 a)
|
||||
{
|
||||
if(Pico.m.z80Run&1) return 0;
|
||||
|
||||
a&=0x1fff;
|
||||
|
||||
if(!(PicoOpt&4)) {
|
||||
// Z80 disabled, do some faking
|
||||
static u8 zerosent = 0;
|
||||
if(a == Pico.m.z80_lastaddr) { // probably polling something
|
||||
u8 d = Pico.m.z80_fakeval;
|
||||
if((d & 0xf) == 0xf && !zerosent) {
|
||||
d = 0; zerosent = 1;
|
||||
} else {
|
||||
Pico.m.z80_fakeval++;
|
||||
zerosent = 0;
|
||||
}
|
||||
return d;
|
||||
} else {
|
||||
Pico.m.z80_fakeval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Pico.m.z80_lastaddr = (u16) a;
|
||||
return Pico.zram[a];
|
||||
}
|
||||
|
||||
|
||||
// for nonstandard reads
|
||||
static u32 UnusualRead16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
dprintf("unusual r%i: %06x @%06x", realsize&~1, (a&0xfffffe)+(realsize&1), SekPc);
|
||||
|
||||
|
||||
dprintf("ret = %04x", d);
|
||||
return d;
|
||||
}
|
||||
|
||||
static u32 OtherRead16(u32 a, int realsize)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xff0000)==0xa00000) {
|
||||
if ((a&0x4000)==0x0000) { d=z80Read8(a); d|=d<<8; goto end; } // Z80 ram (not byteswaped)
|
||||
if ((a&0x6000)==0x4000) { if(PicoOpt&1) d=YM2612Read(); else d=Pico.m.rotate++&3; goto end; } // 0x4000-0x5fff, Fudge if disabled
|
||||
d=0xffff; goto end;
|
||||
}
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
switch(a) {
|
||||
case 0: d=Pico.m.hardware; break; // Hardware value (Version register)
|
||||
case 1: d=PadRead(0); d|=Pico.ioports[1]&0x80; break;
|
||||
case 2: d=PadRead(1); d|=Pico.ioports[2]&0x80; break;
|
||||
default: d=Pico.ioports[a]; break; // IO ports can be used as RAM
|
||||
}
|
||||
d|=d<<8;
|
||||
goto end;
|
||||
}
|
||||
// |=0x80 for Shadow of the Beast & Super Offroad; rotate fakes next fetched instruction for Time Killers
|
||||
if (a==0xa11100) { d=((Pico.m.z80Run&1)<<8)|0x8000|Pico.m.rotate++; goto end; }
|
||||
|
||||
if ((a&0xe700e0)==0xc00000) { d=PicoVideoRead(a); goto end; }
|
||||
|
||||
if ((a&0xffffc0)==0xa12000) { d=m68k_reg_read16(a, realsize); goto end; }
|
||||
|
||||
d = UnusualRead16(a, realsize);
|
||||
|
||||
end:
|
||||
return d;
|
||||
}
|
||||
|
||||
//extern UINT32 mz80GetRegisterValue(void *, UINT32);
|
||||
|
||||
static void OtherWrite8(u32 a,u32 d,int realsize)
|
||||
{
|
||||
if ((a&0xe700f9)==0xc00011||(a&0xff7ff9)==0xa07f11) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound
|
||||
if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d; return; } // Z80 ram
|
||||
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d); return; } // FM Sound
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
// 6 button gamepad: if TH went from 0 to 1, gamepad changes state
|
||||
if(PicoOpt&0x20) {
|
||||
if(a==1) {
|
||||
Pico.m.padDelay[0] = 0;
|
||||
if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++;
|
||||
}
|
||||
else if(a==2) {
|
||||
Pico.m.padDelay[1] = 0;
|
||||
if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++;
|
||||
}
|
||||
}
|
||||
Pico.ioports[a]=(u8)d; // IO ports can be used as RAM
|
||||
return;
|
||||
}
|
||||
if (a==0xa11100) {
|
||||
extern int z80startCycle, z80stopCycle;
|
||||
//int lineCycles=(488-SekCyclesLeft)&0x1ff;
|
||||
d&=1; d^=1;
|
||||
if(!d) {
|
||||
// hack: detect a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III)
|
||||
if((PicoOpt&4) && Pico.m.z80Run==1) z80_run(20);
|
||||
z80stopCycle = SekCyclesDone();
|
||||
//z80ExtraCycles += (lineCycles>>1)-(lineCycles>>5); // only meaningful in PicoFrameHints()
|
||||
} else {
|
||||
z80startCycle = SekCyclesDone();
|
||||
//if(Pico.m.scanline != -1)
|
||||
//z80ExtraCycles -= (lineCycles>>1)-(lineCycles>>5)+16;
|
||||
}
|
||||
//dprintf("set_zrun: %i [%i|%i] zPC=%04x @%06x", d, Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0), SekPc);
|
||||
Pico.m.z80Run=(u8)d; return;
|
||||
}
|
||||
if (a==0xa11200) { if(!(d&1)) z80_reset(); return; }
|
||||
|
||||
if ((a&0xff7f00)==0xa06000) // Z80 BANK register
|
||||
{
|
||||
Pico.m.z80_bank68k>>=1;
|
||||
Pico.m.z80_bank68k|=(d&1)<<8;
|
||||
Pico.m.z80_bank68k&=0x1ff; // 9 bits and filled in the new top one
|
||||
return;
|
||||
}
|
||||
|
||||
if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)(d|(d<<8))); return; } // Byte access gets mirrored
|
||||
|
||||
if ((a&0xffffc0)==0xa12000) { m68k_reg_write8(a, d, realsize); return; }
|
||||
|
||||
dprintf("strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc);
|
||||
}
|
||||
|
||||
static void OtherWrite16(u32 a,u32 d)
|
||||
{
|
||||
if ((a&0xe700e0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; }
|
||||
if ((a&0xff4000)==0xa00000) { if(!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8); return; } // Z80 ram (MSB only)
|
||||
|
||||
if ((a&0xffffe0)==0xa10000) { // I/O ports
|
||||
a=(a>>1)&0xf;
|
||||
// 6 button gamepad: if TH went from 0 to 1, gamepad changes state
|
||||
if(PicoOpt&0x20) {
|
||||
if(a==1) {
|
||||
Pico.m.padDelay[0] = 0;
|
||||
if(!(Pico.ioports[1]&0x40) && (d&0x40)) Pico.m.padTHPhase[0]++;
|
||||
}
|
||||
else if(a==2) {
|
||||
Pico.m.padDelay[1] = 0;
|
||||
if(!(Pico.ioports[2]&0x40) && (d&0x40)) Pico.m.padTHPhase[1]++;
|
||||
}
|
||||
}
|
||||
Pico.ioports[a]=(u8)d; // IO ports can be used as RAM
|
||||
return;
|
||||
}
|
||||
if (a==0xa11100) { OtherWrite8(a, d>>8, 16); return; }
|
||||
if (a==0xa11200) { if(!(d&0x100)) z80_reset(); return; }
|
||||
|
||||
OtherWrite8(a, d>>8, 16);
|
||||
OtherWrite8(a+1,d&0xff, 16);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Read Rom and read Ram
|
||||
|
||||
u8 PicoReadM68k8(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { d = *(u8 *)(Pico.ram+((a^1)&0xffff)); goto end; } // Ram
|
||||
|
||||
a&=0xffffff;
|
||||
|
||||
if (a < 0x20000) { d = *(u8 *)(Pico_mcd->bios+(a^1)); goto end; } // bios
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
d = *(prg_bank+((a^1)&0x1ffff));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((a&0xff4000)==0xa00000) { d=z80Read8(a); goto end; } // Z80 Ram
|
||||
|
||||
d=OtherRead16(a&~1, 8|(a&1)); if ((a&1)==0) d>>=8;
|
||||
|
||||
end:
|
||||
|
||||
#ifdef __debug_io
|
||||
dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc);
|
||||
#endif
|
||||
return (u8)d;
|
||||
}
|
||||
|
||||
u16 PicoReadM68k16(u32 a)
|
||||
{
|
||||
u16 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { d=*(u16 *)(Pico.ram+(a&0xfffe)); goto end; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
if (a < 0x20000) { d = *(u16 *)(Pico_mcd->bios+a); goto end; } // bios
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
d = *(u16 *)(prg_bank+(a&0x1fffe));
|
||||
goto end;
|
||||
}
|
||||
|
||||
d = (u16)OtherRead16(a, 16);
|
||||
|
||||
end:
|
||||
|
||||
#ifdef __debug_io
|
||||
dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
u32 PicoReadM68k32(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); d = (pm[0]<<16)|pm[1]; goto end; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
if (a < 0x20000) { u16 *pm=(u16 *)(Pico_mcd->bios+a); d = (pm[0]<<16)|pm[1]; goto end; } // bios
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
u16 *pm=(u16 *)(prg_bank+(a&0x1fffe));
|
||||
d = (pm[0]<<16)|pm[1];
|
||||
goto end;
|
||||
}
|
||||
|
||||
d = (OtherRead16(a, 32)<<16)|OtherRead16(a+2, 32);
|
||||
|
||||
end:
|
||||
#ifdef __debug_io
|
||||
dprintf("r32: %06x, %08x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Write Ram
|
||||
|
||||
void PicoWriteM68k8(u32 a,u8 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
|
||||
#endif
|
||||
//if ((a&0xe0ffff)==0xe0a9ba+0x69c)
|
||||
// dprintf("w8 : %06x, %02x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { u8 *pm=(u8 *)(Pico.ram+((a^1)&0xffff)); pm[0]=d; return; } // Ram
|
||||
|
||||
a&=0xffffff;
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
u8 *pm=(u8 *)(prg_bank+((a^1)&0x1ffff));
|
||||
*pm=d;
|
||||
return;
|
||||
}
|
||||
|
||||
OtherWrite8(a,d,8);
|
||||
}
|
||||
|
||||
void PicoWriteM68k16(u32 a,u16 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w16: %06x, %04x", a&0xffffff, d);
|
||||
#endif
|
||||
//if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c)
|
||||
// dprintf("w16: %06x, %04x @%06x", a&0xffffff, d, SekPc);
|
||||
|
||||
if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
*(u16 *)(prg_bank+(a&0x1fffe))=d;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OtherWrite16(a,d);
|
||||
}
|
||||
|
||||
void PicoWriteM68k32(u32 a,u32 d)
|
||||
{
|
||||
#ifdef __debug_io
|
||||
dprintf("w32: %06x, %08x", a&0xffffff, d);
|
||||
#endif
|
||||
|
||||
if ((a&0xe00000)==0xe00000)
|
||||
{
|
||||
// Ram:
|
||||
u16 *pm=(u16 *)(Pico.ram+(a&0xfffe));
|
||||
pm[0]=(u16)(d>>16); pm[1]=(u16)d;
|
||||
return;
|
||||
}
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if ((a&0xfe0000)==0x020000) {
|
||||
u8 *prg_bank = Pico_mcd->prg_ram_b[Pico_mcd->m68k_regs[3]>>6];
|
||||
u16 *pm=(u16 *)(prg_bank+(a&0x1fffe));
|
||||
pm[0]=(u16)(d>>16); pm[1]=(u16)d;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OtherWrite16(a, (u16)(d>>16));
|
||||
OtherWrite16(a+2,(u16)d);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
u8 PicoReadS68k8(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
a&=0xffffff;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
d = *(Pico_mcd->prg_ram+(a^1));
|
||||
goto end;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
d = s68k_reg_read16(a&~1, 8|(a&1)); if ((a&1)==0) d>>=8;
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("s68k r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPcS68k);
|
||||
|
||||
end:
|
||||
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPcS68k);
|
||||
#endif
|
||||
return (u8)d;
|
||||
}
|
||||
|
||||
u16 PicoReadS68k16(u32 a)
|
||||
{
|
||||
u16 d=0;
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
d = *(u16 *)(Pico_mcd->prg_ram+a);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
d = s68k_reg_read16(a, 16);
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("s68k r16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
|
||||
end:
|
||||
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k r16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
u32 PicoReadS68k32(u32 a)
|
||||
{
|
||||
u32 d=0;
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
u16 *pm=(u16 *)(Pico_mcd->prg_ram+a);
|
||||
d = (pm[0]<<16)|pm[1];
|
||||
goto end;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
d = (s68k_reg_read16(a, 32)<<16)|s68k_reg_read16(a+2, 32);
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("s68k r32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
|
||||
end:
|
||||
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k r32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
void PicoWriteS68k8(u32 a,u8 d)
|
||||
{
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k w8 : %06x, %02x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
#endif
|
||||
|
||||
a&=0xffffff;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
u8 *pm=(u8 *)(Pico_mcd->prg_ram+(a^1));
|
||||
*pm=d;
|
||||
return;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
s68k_reg_write8(a,d,8);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("s68k w8 : %06x, %02x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
}
|
||||
|
||||
void PicoWriteS68k16(u32 a,u16 d)
|
||||
{
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k w16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
#endif
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
*(u16 *)(Pico_mcd->prg_ram+a)=d;
|
||||
return;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
s68k_reg_write8(a, d>>8, 16);
|
||||
s68k_reg_write8(a+1,d&0xff, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("s68k w16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
}
|
||||
|
||||
void PicoWriteS68k32(u32 a,u32 d)
|
||||
{
|
||||
#ifdef __debug_io2
|
||||
dprintf("s68k w32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
#endif
|
||||
|
||||
a&=0xfffffe;
|
||||
|
||||
// prg RAM
|
||||
if (a < 0x80000) {
|
||||
u16 *pm=(u16 *)(Pico_mcd->prg_ram+a);
|
||||
pm[0]=(u16)(d>>16); pm[1]=(u16)d;
|
||||
return;
|
||||
}
|
||||
|
||||
// regs
|
||||
if ((a&0xfffe00) == 0xff8000) {
|
||||
s68k_reg_write8(a, d>>24, 32);
|
||||
s68k_reg_write8(a+1,(d>>16)&0xff, 32);
|
||||
s68k_reg_write8(a+2,(d>>8) &0xff, 32);
|
||||
s68k_reg_write8(a+3, d &0xff, 32);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("s68k w32: %06x, %08x @%06x", a&0xffffff, d, SekPcS68k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
#ifdef EMU_M68K
|
||||
unsigned char PicoReadCD8w (unsigned int a) {
|
||||
return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k8(a) : PicoReadM68k8(a);
|
||||
}
|
||||
unsigned short PicoReadCD16w(unsigned int a) {
|
||||
return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k16(a) : PicoReadM68k16(a);
|
||||
}
|
||||
unsigned int PicoReadCD32w(unsigned int a) {
|
||||
return m68ki_cpu_p == &PicoS68kCPU ? PicoReadS68k32(a) : PicoReadM68k32(a);
|
||||
}
|
||||
void PicoWriteCD8w (unsigned int a, unsigned char d) {
|
||||
if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k8(a, d); else PicoWriteM68k8(a, d);
|
||||
}
|
||||
void PicoWriteCD16w(unsigned int a, unsigned short d) {
|
||||
if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k16(a, d); else PicoWriteM68k16(a, d);
|
||||
}
|
||||
void PicoWriteCD32w(unsigned int a, unsigned int d) {
|
||||
if (m68ki_cpu_p == &PicoS68kCPU) PicoWriteS68k32(a, d); else PicoWriteM68k32(a, d);
|
||||
}
|
||||
|
||||
// these are allowed to access RAM
|
||||
unsigned int m68k_read_pcrelative_CD8 (unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(m68ki_cpu_p == &PicoS68kCPU) {
|
||||
if (a < 0x80000) return *(u8 *)(Pico_mcd->prg_ram+(a^1)); // PRG Ram
|
||||
else dprintf("s68k read_pcrel8 @ %06x", a);
|
||||
} else {
|
||||
if(a<Pico.romsize) return *(u8 *)(Pico.rom+(a^1)); // Rom
|
||||
if((a&0xe00000)==0xe00000) return *(u8 *)(Pico.ram+((a^1)&0xffff)); // Ram
|
||||
}
|
||||
return 0;//(u8) lastread_d;
|
||||
}
|
||||
unsigned int m68k_read_pcrelative_CD16(unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(m68ki_cpu_p == &PicoS68kCPU) {
|
||||
if (a < 0x80000) return *(u16 *)(Pico_mcd->prg_ram+(a&~1)); // PRG Ram
|
||||
else dprintf("s68k read_pcrel16 @ %06x", a);
|
||||
} else {
|
||||
if(a<Pico.romsize) return *(u16 *)(Pico.rom+(a&~1)); // Rom
|
||||
if((a&0xe00000)==0xe00000) return *(u16 *)(Pico.ram+(a&0xfffe)); // Ram
|
||||
}
|
||||
return 0;//(u16) lastread_d;
|
||||
}
|
||||
unsigned int m68k_read_pcrelative_CD32(unsigned int a) {
|
||||
a&=0xffffff;
|
||||
if(m68ki_cpu_p == &PicoS68kCPU) {
|
||||
if (a < 0x80000) { u16 *pm=(u16 *)(Pico_mcd->prg_ram+(a&~1)); return (pm[0]<<16)|pm[1]; } // PRG Ram
|
||||
else dprintf("s68k read_pcrel32 @ %06x", a);
|
||||
} else {
|
||||
if(a<Pico.romsize) { u16 *pm=(u16 *)(Pico.rom+(a&~1)); return (pm[0]<<16)|pm[1]; }
|
||||
if((a&0xe00000)==0xe00000) { u16 *pm=(u16 *)(Pico.ram+(a&0xfffe)); return (pm[0]<<16)|pm[1]; } // Ram
|
||||
}
|
||||
return 0; //lastread_d;
|
||||
}
|
||||
#endif // EMU_M68K
|
||||
|
213
Pico/cd/Pico.c
Normal file
213
Pico/cd/Pico.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "../PicoInt.h"
|
||||
#include "../sound/sound.h"
|
||||
|
||||
|
||||
int counter75hz = 0;
|
||||
|
||||
|
||||
int PicoInitMCD(void)
|
||||
{
|
||||
SekInitS68k();
|
||||
Init_CD_Driver();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PicoExitMCD(void)
|
||||
{
|
||||
End_CD_Driver();
|
||||
}
|
||||
|
||||
int PicoResetMCD(int hard)
|
||||
{
|
||||
// clear everything except BIOS
|
||||
memset(Pico_mcd->prg_ram, 0, sizeof(mcd_state) - sizeof(Pico_mcd->bios));
|
||||
PicoMCD |= 2; // s68k reset pending
|
||||
counter75hz = 0;
|
||||
|
||||
LC89510_Reset();
|
||||
Reset_CD();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline void SekRun(int cyc)
|
||||
{
|
||||
int cyc_do;
|
||||
SekCycleAim+=cyc;
|
||||
if((cyc_do=SekCycleAim-SekCycleCnt) < 0) return;
|
||||
#if defined(EMU_M68K)
|
||||
m68k_set_context(&PicoM68kCPU);
|
||||
SekCycleCnt+=m68k_execute(cyc_do);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void SekRunS68k(int cyc)
|
||||
{
|
||||
int cyc_do;
|
||||
SekCycleAimS68k+=cyc;
|
||||
if((cyc_do=SekCycleAimS68k-SekCycleCntS68k) < 0) return;
|
||||
#if defined(EMU_M68K)
|
||||
m68k_set_context(&PicoS68kCPU);
|
||||
SekCycleCntS68k+=m68k_execute(cyc_do);
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: tidy
|
||||
extern unsigned char m68k_regs[0x40];
|
||||
extern unsigned char s68k_regs[0x200];
|
||||
|
||||
// Accurate but slower frame which does hints
|
||||
static int PicoFrameHintsMCD(void)
|
||||
{
|
||||
struct PicoVideo *pv=&Pico.video;
|
||||
int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample;
|
||||
const int cycles_68k=488,cycles_z80=228,cycles_s68k=795; // both PAL and NTSC compile to same values
|
||||
int skip=PicoSkipFrame || (PicoOpt&0x10);
|
||||
int hint; // Hint counter
|
||||
|
||||
if(Pico.m.pal) { //
|
||||
//cycles_68k = (int) ((double) OSC_PAL / 7 / 50 / 312 + 0.4); // should compile to a constant (488)
|
||||
//cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228
|
||||
lines = 312; // Steve Snake says there are 313 lines, but this seems to also work well
|
||||
line_sample = 68;
|
||||
if(pv->reg[1]&8) lines_vis = 240;
|
||||
} else {
|
||||
//cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488
|
||||
//cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
|
||||
lines = 262;
|
||||
line_sample = 93;
|
||||
}
|
||||
|
||||
SekCyclesReset();
|
||||
SekCyclesResetS68k();
|
||||
//z80ExtraCycles = 0;
|
||||
|
||||
if(PicoOpt&4)
|
||||
z80CycleAim = 0;
|
||||
// z80_resetCycles();
|
||||
|
||||
pv->status&=~0x88; // clear V-Int, come out of vblank
|
||||
|
||||
hint=pv->reg[10]; // Load H-Int counter
|
||||
//dprintf("-hint: %i", hint);
|
||||
|
||||
for (y=0;y<lines;y++)
|
||||
{
|
||||
Pico.m.scanline=(short)y;
|
||||
|
||||
// pad delay (for 6 button pads)
|
||||
if(PicoOpt&0x20) {
|
||||
if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0;
|
||||
if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0;
|
||||
}
|
||||
|
||||
// H-Interrupts:
|
||||
if(y <= lines_vis && --hint < 0) // y <= lines_vis: Comix Zone, Golden Axe
|
||||
{
|
||||
//dprintf("rhint:old @ %06x", SekPc);
|
||||
hint=pv->reg[10]; // Reload H-Int counter
|
||||
pv->pending_ints|=0x10;
|
||||
if (pv->reg[0]&0x10) SekInterrupt(4);
|
||||
//dprintf("rhint: %i @ %06x [%i|%i]", hint, SekPc, y, SekCycleCnt);
|
||||
//dprintf("hint_routine: %x", (*(unsigned short*)(Pico.ram+0x0B84)<<16)|*(unsigned short*)(Pico.ram+0x0B86));
|
||||
}
|
||||
|
||||
// V-Interrupt:
|
||||
if (y == lines_vis)
|
||||
{
|
||||
//dprintf("vint: @ %06x [%i|%i]", SekPc, y, SekCycleCnt);
|
||||
pv->status|=0x88; // V-Int happened, go into vblank
|
||||
SekRun(128); SekCycleAim-=128; // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula)
|
||||
/*if(Pico.m.z80Run && (PicoOpt&4)) {
|
||||
z80CycleAim+=cycles_z80/2;
|
||||
total_z80+=z80_run(z80CycleAim-total_z80);
|
||||
z80CycleAim-=cycles_z80/2;
|
||||
}*/
|
||||
pv->pending_ints|=0x20;
|
||||
if(pv->reg[1]&0x20) SekInterrupt(6);
|
||||
if(Pico.m.z80Run && (PicoOpt&4)) // ?
|
||||
z80_int();
|
||||
//dprintf("zint: [%i|%i] zPC=%04x", Pico.m.scanline, SekCyclesDone(), mz80GetRegisterValue(NULL, 0));
|
||||
}
|
||||
|
||||
// decide if we draw this line
|
||||
#if CAN_HANDLE_240_LINES
|
||||
if(!skip && ((!(pv->reg[1]&8) && y<224) || ((pv->reg[1]&8) && y<240)) )
|
||||
#else
|
||||
if(!skip && y<224)
|
||||
#endif
|
||||
PicoLine(y);
|
||||
|
||||
if(PicoOpt&1)
|
||||
sound_timers_and_dac(y);
|
||||
|
||||
// get samples from sound chips
|
||||
if(y == 32 && PsndOut)
|
||||
emustatus &= ~1;
|
||||
else if((y == 224 || y == line_sample) && PsndOut)
|
||||
;//getSamples(y);
|
||||
|
||||
// Run scanline:
|
||||
//dprintf("m68k starting exec @ %06x", SekPc);
|
||||
SekRun(cycles_68k);
|
||||
if ((Pico_mcd->m68k_regs[1]&3) == 1) { // no busreq/no reset
|
||||
#if 0
|
||||
int i;
|
||||
FILE *f = fopen("prg_ram.bin", "wb");
|
||||
for (i = 0; i < 0x80000; i+=2)
|
||||
{
|
||||
int tmp = Pico_mcd->prg_ram[i];
|
||||
Pico_mcd->prg_ram[i] = Pico_mcd->prg_ram[i+1];
|
||||
Pico_mcd->prg_ram[i+1] = tmp;
|
||||
}
|
||||
fwrite(Pico_mcd->prg_ram, 1, 0x80000, f);
|
||||
fclose(f);
|
||||
exit(1);
|
||||
#endif
|
||||
//dprintf("s68k starting exec @ %06x", SekPcS68k);
|
||||
SekRunS68k(cycles_s68k);
|
||||
}
|
||||
|
||||
if((PicoOpt&4) && Pico.m.z80Run) {
|
||||
Pico.m.z80Run|=2;
|
||||
z80CycleAim+=cycles_z80;
|
||||
total_z80+=z80_run(z80CycleAim-total_z80);
|
||||
}
|
||||
|
||||
// if cdd is on, counter elapsed and irq4 is not masked, do irq4
|
||||
if ((Pico_mcd->s68k_regs[0x37]&4) && ++counter75hz > 209 && (Pico_mcd->s68k_regs[0x33]&(1<<4))) {
|
||||
counter75hz = 0;
|
||||
Check_CD_Command();
|
||||
}
|
||||
}
|
||||
|
||||
// draw a frame just after vblank in alternative render mode
|
||||
if(!PicoSkipFrame && (PicoOpt&0x10))
|
||||
PicoFrameFull();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PicoFrameMCD(void)
|
||||
{
|
||||
if(!(PicoOpt&0x10))
|
||||
PicoFrameStart();
|
||||
|
||||
PicoFrameHintsMCD();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
78
Pico/cd/Sek.c
Normal file
78
Pico/cd/Sek.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include "../PicoInt.h"
|
||||
|
||||
|
||||
int SekCycleCntS68k=0; // cycles done in this frame
|
||||
int SekCycleAimS68k=0; // cycle aim
|
||||
|
||||
#ifdef EMU_M68K
|
||||
// ---------------------- MUSASHI 68000 ----------------------
|
||||
m68ki_cpu_core PicoS68kCPU; // Mega CD's CPU
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EMU_M68K
|
||||
int SekIntAckS68k(int level)
|
||||
{
|
||||
dprintf("s68k: int %i ack [%i|%i]", level, Pico.m.scanline, SekCyclesDone());
|
||||
CPU_INT_LEVEL = 0;
|
||||
return M68K_INT_ACK_AUTOVECTOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int SekInitS68k()
|
||||
{
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
// Musashi is not very context friendly..
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoS68kCPU);
|
||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
m68k_init();
|
||||
m68k_set_int_ack_callback(SekIntAckS68k);
|
||||
// m68k_pulse_reset(); // not yet, memmap is not set up
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset the 68000:
|
||||
int SekResetS68k()
|
||||
{
|
||||
if (Pico.rom==NULL) return 1;
|
||||
|
||||
#ifdef EMU_M68K
|
||||
{
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
|
||||
m68k_set_context(&PicoS68kCPU);
|
||||
m68k_pulse_reset();
|
||||
m68k_set_context(oldcontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SekInterruptS68k(int irq)
|
||||
{
|
||||
#ifdef EMU_M68K
|
||||
void *oldcontext = m68ki_cpu_p;
|
||||
m68k_set_context(&PicoS68kCPU);
|
||||
m68k_set_irq(irq); // raise irq (gets lowered after taken or must be done in ack)
|
||||
m68k_set_context(oldcontext);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
996
Pico/cd/cd_sys.c
Normal file
996
Pico/cd/cd_sys.c
Normal file
|
@ -0,0 +1,996 @@
|
|||
#include <stdio.h>
|
||||
#include "cd_sys.h"
|
||||
//#include "cd_file.h"
|
||||
|
||||
#include "../PicoInt.h"
|
||||
|
||||
#define cdprintf printf
|
||||
//#define cdprintf(x...)
|
||||
|
||||
#define TRAY_OPEN 0x0500 // TRAY OPEN CDD status
|
||||
#define NOCD 0x0000 // CD removed CDD status
|
||||
#define STOPPED 0x0900 // STOPPED CDD status (happen after stop or close tray command)
|
||||
#define READY 0x0400 // READY CDD status (also used for seeking)
|
||||
#define FAST_FOW 0x0300 // FAST FORWARD track CDD status
|
||||
#define FAST_REV 0x10300 // FAST REVERSE track CDD status
|
||||
#define PLAYING 0x0100 // PLAYING audio track CDD status
|
||||
|
||||
/*
|
||||
#include "gens.h"
|
||||
#include "G_dsound.h"
|
||||
#include "cdda_mp3.h"
|
||||
#include "lc89510.h"
|
||||
#include "Star_68k.h"
|
||||
#include "Mem_M68K.h"
|
||||
#include "Mem_S68K.h"
|
||||
#include "save.h"
|
||||
#include "misc.h"
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
int CDDA_Enable;
|
||||
|
||||
int CD_Audio_Buffer_L[8192];
|
||||
int CD_Audio_Buffer_R[8192];
|
||||
int CD_Audio_Buffer_Read_Pos = 0;
|
||||
int CD_Audio_Buffer_Write_Pos = 2000;
|
||||
int CD_Audio_Starting;
|
||||
*/
|
||||
|
||||
static int CD_Present = 0;
|
||||
int CD_Timer_Counter = 0; // TODO: check refs
|
||||
|
||||
static int CDD_Complete;
|
||||
|
||||
static int File_Add_Delay = 0;
|
||||
|
||||
//_scd SCD;
|
||||
|
||||
|
||||
|
||||
#define CHECK_TRAY_OPEN \
|
||||
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) \
|
||||
{ \
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
|
||||
\
|
||||
Pico_mcd->cdd.Minute = 0; \
|
||||
Pico_mcd->cdd.Seconde = 0; \
|
||||
Pico_mcd->cdd.Frame = 0; \
|
||||
Pico_mcd->cdd.Ext = 0; \
|
||||
\
|
||||
CDD_Complete = 1; \
|
||||
\
|
||||
return 2; \
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_CD_PRESENT \
|
||||
if (!CD_Present) \
|
||||
{ \
|
||||
Pico_mcd->scd.Status_CDD = NOCD; \
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
|
||||
\
|
||||
Pico_mcd->cdd.Minute = 0; \
|
||||
Pico_mcd->cdd.Seconde = 0; \
|
||||
Pico_mcd->cdd.Frame = 0; \
|
||||
Pico_mcd->cdd.Ext = 0; \
|
||||
\
|
||||
CDD_Complete = 1; \
|
||||
\
|
||||
return 3; \
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void MSB2DWORD(unsigned int *d, unsigned char *b)
|
||||
{
|
||||
unsigned int retVal;
|
||||
|
||||
retVal = (unsigned int )b[0];
|
||||
retVal = (retVal<<8) + (unsigned int )b[1];
|
||||
retVal = (retVal<<8) + (unsigned int )b[2];
|
||||
retVal = (retVal<<8) + (unsigned int )b[3];
|
||||
|
||||
*d = retVal;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int MSF_to_LBA(_msf *MSF)
|
||||
{
|
||||
return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;
|
||||
}
|
||||
|
||||
|
||||
void LBA_to_MSF(int lba, _msf *MSF)
|
||||
{
|
||||
if (lba < -150) lba = 0;
|
||||
else lba += 150;
|
||||
MSF->M = lba / (60 * 75);
|
||||
MSF->S = (lba / 75) % 60;
|
||||
MSF->F = lba % 75;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int MSF_to_Track(_msf *MSF)
|
||||
{
|
||||
int i, Start, Cur;
|
||||
|
||||
Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;
|
||||
|
||||
for(i = Pico_mcd->scd.TOC.First_Track; i <= (Pico_mcd->scd.TOC.Last_Track + 1); i++)
|
||||
{
|
||||
Cur = Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.M << 16;
|
||||
Cur += Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.S << 8;
|
||||
Cur += Pico_mcd->scd.TOC.Tracks[i - Pico_mcd->scd.TOC.First_Track].MSF.F;
|
||||
|
||||
if (Cur > Start) break;
|
||||
}
|
||||
|
||||
--i;
|
||||
|
||||
if (i > Pico_mcd->scd.TOC.Last_Track) return 100;
|
||||
if (i < Pico_mcd->scd.TOC.First_Track) i = Pico_mcd->scd.TOC.First_Track;
|
||||
|
||||
return (unsigned) i;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int LBA_to_Track(int lba)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
LBA_to_MSF(lba, &MSF);
|
||||
return MSF_to_Track(&MSF);
|
||||
}
|
||||
|
||||
|
||||
static void Track_to_MSF(int track, _msf *MSF)
|
||||
{
|
||||
if (track < Pico_mcd->scd.TOC.First_Track) track = Pico_mcd->scd.TOC.First_Track;
|
||||
else if (track > Pico_mcd->scd.TOC.Last_Track) track = Pico_mcd->scd.TOC.Last_Track;
|
||||
|
||||
MSF->M = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.M;
|
||||
MSF->S = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.S;
|
||||
MSF->F = Pico_mcd->scd.TOC.Tracks[track - Pico_mcd->scd.TOC.First_Track].MSF.F;
|
||||
}
|
||||
|
||||
|
||||
int Track_to_LBA(int track)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
Track_to_MSF(track, &MSF);
|
||||
return MSF_to_LBA(&MSF);
|
||||
}
|
||||
|
||||
|
||||
void Check_CD_Command(void)
|
||||
{
|
||||
cdprintf("CHECK CD COMMAND\n");
|
||||
|
||||
// Check CDD
|
||||
|
||||
if (CDD_Complete)
|
||||
{
|
||||
CDD_Complete = 0;
|
||||
|
||||
CDD_Export_Status();
|
||||
}
|
||||
|
||||
// Check CDC
|
||||
|
||||
if (Pico_mcd->scd.Status_CDC & 1) // CDC is reading data ...
|
||||
{
|
||||
cdprintf("Sending a read command\n");
|
||||
|
||||
// DATA ?
|
||||
if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type)
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01;
|
||||
else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
|
||||
if (File_Add_Delay == 0)
|
||||
{
|
||||
#if 0 // TODO
|
||||
FILE_Read_One_LBA_CDC();
|
||||
#endif
|
||||
}
|
||||
else File_Add_Delay--;
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Status_CDD == FAST_FOW)
|
||||
{
|
||||
Pico_mcd->scd.Cur_LBA += 10;
|
||||
CDC_Update_Header();
|
||||
|
||||
}
|
||||
else if (Pico_mcd->scd.Status_CDD == FAST_REV)
|
||||
{
|
||||
Pico_mcd->scd.Cur_LBA -= 10;
|
||||
if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;
|
||||
CDC_Update_Header();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Init_CD_Driver(void)
|
||||
{
|
||||
#if 0 // TODO
|
||||
FILE_Init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void End_CD_Driver(void)
|
||||
{
|
||||
#if 0 // TODO
|
||||
FILE_End();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Reset_CD(void)
|
||||
{
|
||||
Pico_mcd->scd.Cur_Track = 0;
|
||||
Pico_mcd->scd.Cur_LBA = -150;
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
CDD_Complete = 0;
|
||||
}
|
||||
|
||||
|
||||
int Insert_CD(char *buf, char *iso_name)
|
||||
{
|
||||
// memset(CD_Audio_Buffer_L, 0, 4096 * 4);
|
||||
// memset(CD_Audio_Buffer_R, 0, 4096 * 4);
|
||||
|
||||
if (iso_name == NULL)
|
||||
{
|
||||
CD_Present = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0 // TODO
|
||||
Load_ISO(buf, iso_name);
|
||||
CD_Present = 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Stop_CD(void)
|
||||
{
|
||||
#if 0 // TODO
|
||||
Unload_ISO();
|
||||
#endif
|
||||
CD_Present = 0;
|
||||
}
|
||||
|
||||
|
||||
void Change_CD(void)
|
||||
{
|
||||
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();
|
||||
else Open_Tray_CDD_cD();
|
||||
}
|
||||
|
||||
|
||||
int Get_Status_CDD_c0(void)
|
||||
{
|
||||
cdprintf("Status command : Cur LBA = %d\n", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
// Clear immediat status
|
||||
if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)
|
||||
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Stop_CDD_c1(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;
|
||||
else Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status = 0x0000;
|
||||
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_Pos_CDD_c20(void)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
cdprintf("command 200 : Cur LBA = %d\n", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
cdprintf("Status CDD = %.4X Status = %.4X\n", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
|
||||
|
||||
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_Track_Pos_CDD_c21(void)
|
||||
{
|
||||
int elapsed_time;
|
||||
_msf MSF;
|
||||
|
||||
cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));
|
||||
LBA_to_MSF(elapsed_time - 150, &MSF);
|
||||
|
||||
cdprintf(" elapsed = %d\n", elapsed_time);
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_Current_Track_CDD_c22(void)
|
||||
{
|
||||
cdprintf("Status CDD = %.4X Status = %.4X\n", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_Total_Lenght_CDD_c23(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track -
|
||||
Pico_mcd->scd.TOC.First_Track + 1].MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track -
|
||||
Pico_mcd->scd.TOC.First_Track + 1].MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.TOC.Last_Track -
|
||||
Pico_mcd->scd.TOC.First_Track + 1].MSF.F);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
// FIXME: remove
|
||||
Pico_mcd->cdd.Seconde = 2;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_First_Last_Track_CDD_c24(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.First_Track);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Last_Track);
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
// FIXME: remove
|
||||
Pico_mcd->cdd.Minute = Pico_mcd->cdd.Seconde = 1;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Get_Track_Adr_CDD_c25(void)
|
||||
{
|
||||
int track_number;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
// track number in TC4 & TC5
|
||||
|
||||
track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
|
||||
Pico_mcd->cdd.Status &= 0xFF;
|
||||
if (!CD_Present)
|
||||
{
|
||||
Pico_mcd->scd.Status_CDD = NOCD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
}
|
||||
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
|
||||
|
||||
if (track_number > Pico_mcd->scd.TOC.Last_Track) track_number = Pico_mcd->scd.TOC.Last_Track;
|
||||
else if (track_number < Pico_mcd->scd.TOC.First_Track) track_number = Pico_mcd->scd.TOC.First_Track;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.M);
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.S);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].MSF.F);
|
||||
Pico_mcd->cdd.Ext = track_number % 10;
|
||||
|
||||
if (Pico_mcd->scd.TOC.Tracks[track_number - Pico_mcd->scd.TOC.First_Track].Type) Pico_mcd->cdd.Frame |= 0x0800;
|
||||
|
||||
CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Play_CDD_c3(void)
|
||||
{
|
||||
_msf MSF;
|
||||
int delay, new_lba;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
// MSF of the track to play in TC buffer
|
||||
|
||||
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
|
||||
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
|
||||
|
||||
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
|
||||
|
||||
new_lba = MSF_to_LBA(&MSF);
|
||||
delay = new_lba - Pico_mcd->scd.Cur_LBA;
|
||||
if (delay < 0) delay = -delay;
|
||||
delay >>= 12;
|
||||
|
||||
Pico_mcd->scd.Cur_LBA = new_lba;
|
||||
CDC_Update_Header();
|
||||
|
||||
cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d\n", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
|
||||
|
||||
if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;
|
||||
|
||||
Pico_mcd->scd.Status_CDD = PLAYING;
|
||||
Pico_mcd->cdd.Status = 0x0102;
|
||||
// Pico_mcd->cdd.Status = COMM_OK;
|
||||
|
||||
if (File_Add_Delay == 0) File_Add_Delay = delay;
|
||||
|
||||
if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type)
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
|
||||
}
|
||||
else
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
//CD_Audio_Starting = 1;
|
||||
#if 0 // TODO
|
||||
FILE_Play_CD_LBA();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
|
||||
|
||||
CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Seek_CDD_c4(void)
|
||||
{
|
||||
_msf MSF;
|
||||
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
// MSF to seek in TC buffer
|
||||
|
||||
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
|
||||
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
|
||||
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
|
||||
|
||||
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
|
||||
Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);
|
||||
CDC_Update_Header();
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = 0x0200;
|
||||
|
||||
// DATA ?
|
||||
if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type)
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01;
|
||||
else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Pause_CDD_c6(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read to start a new one if raw data
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Resume_CDD_c7(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
{
|
||||
_msf MSF;
|
||||
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
|
||||
cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d\n", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
|
||||
}
|
||||
#endif
|
||||
|
||||
Pico_mcd->scd.Status_CDD = PLAYING;
|
||||
Pico_mcd->cdd.Status = 0x0102;
|
||||
|
||||
if (Pico_mcd->scd.TOC.Tracks[Pico_mcd->scd.Cur_Track - Pico_mcd->scd.TOC.First_Track].Type)
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
|
||||
}
|
||||
else
|
||||
{
|
||||
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
|
||||
//CD_Audio_Starting = 1;
|
||||
#if 0 // TODO
|
||||
FILE_Play_CD_LBA();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
|
||||
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
|
||||
|
||||
CDD_Complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Fast_Foward_CDD_c8(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = FAST_FOW;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Fast_Rewind_CDD_c9(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
Pico_mcd->scd.Status_CDD = FAST_REV;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
|
||||
|
||||
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Close_Tray_CDD_cC(void)
|
||||
{
|
||||
//Clear_Sound_Buffer();
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
{
|
||||
#if 0 // TODO
|
||||
char new_iso[1024];
|
||||
|
||||
memset(new_iso, 0, 1024);
|
||||
|
||||
while (!Change_File_L(new_iso, Rom_Dir, "Load SegaCD image file", "SegaCD image file\0*.bin;*.iso;*.raw\0All files\0*.*\0\0", ""));
|
||||
Reload_SegaCD(new_iso);
|
||||
|
||||
CD_Present = 1;
|
||||
#else
|
||||
CD_Present = 0;
|
||||
#endif
|
||||
Pico_mcd->scd.Status_CDD = STOPPED;
|
||||
Pico_mcd->cdd.Status = 0x0000;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
}
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Open_Tray_CDD_cD(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
|
||||
|
||||
#if 0 // TODO
|
||||
Unload_ISO();
|
||||
#endif
|
||||
CD_Present = 0;
|
||||
|
||||
Pico_mcd->scd.Status_CDD = TRAY_OPEN;
|
||||
Pico_mcd->cdd.Status = 0x0E00;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CDD_cA(void)
|
||||
{
|
||||
CHECK_TRAY_OPEN
|
||||
CHECK_CD_PRESENT
|
||||
|
||||
Pico_mcd->scd.Status_CDC &= ~1;
|
||||
|
||||
Pico_mcd->scd.Status_CDD = READY;
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);
|
||||
Pico_mcd->cdd.Frame = INT_TO_BCDW(1);
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
CDD_Complete = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CDD_Def(void)
|
||||
{
|
||||
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
|
||||
|
||||
Pico_mcd->cdd.Minute = 0;
|
||||
Pico_mcd->cdd.Seconde = 0;
|
||||
Pico_mcd->cdd.Frame = 0;
|
||||
Pico_mcd->cdd.Ext = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************
|
||||
* Others CD functions *
|
||||
**************************/
|
||||
|
||||
|
||||
// do we need them?
|
||||
#if 0
|
||||
void Write_CD_Audio(short *Buf, int rate, int channel, int lenght)
|
||||
{
|
||||
unsigned int lenght_src, lenght_dst;
|
||||
unsigned int pos_src, pas_src;
|
||||
|
||||
if (rate == 0) return;
|
||||
if (Sound_Rate == 0) return;
|
||||
|
||||
if (CD_Audio_Starting)
|
||||
{
|
||||
CD_Audio_Starting = 0;
|
||||
memset(CD_Audio_Buffer_L, 0, 4096 * 4);
|
||||
memset(CD_Audio_Buffer_R, 0, 4096 * 4);
|
||||
CD_Audio_Buffer_Write_Pos = (CD_Audio_Buffer_Read_Pos + 2000) & 0xFFF;
|
||||
}
|
||||
|
||||
lenght_src = rate / 75; // 75th of a second
|
||||
lenght_dst = Sound_Rate / 75; // 75th of a second
|
||||
|
||||
pas_src = (lenght_src << 16) / lenght_dst;
|
||||
pos_src = 0;
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
fprintf(debug_SCD_file, "\n********* Write Pos = %d ", CD_Audio_Buffer_Write_Pos);
|
||||
#endif
|
||||
|
||||
if (channel == 2)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov edi, CD_Audio_Buffer_Write_Pos
|
||||
mov ebx, Buf
|
||||
xor esi, esi
|
||||
mov ecx, lenght_dst
|
||||
xor eax, eax
|
||||
mov edx, pas_src
|
||||
dec ecx
|
||||
jmp short loop_stereo
|
||||
|
||||
align 16
|
||||
|
||||
loop_stereo:
|
||||
movsx eax, word ptr [ebx + esi * 4]
|
||||
mov CD_Audio_Buffer_L[edi * 4], eax
|
||||
movsx eax, word ptr [ebx + esi * 4 + 2]
|
||||
mov CD_Audio_Buffer_R[edi * 4], eax
|
||||
mov esi, dword ptr pos_src
|
||||
inc edi
|
||||
add esi, edx
|
||||
and edi, 0xFFF
|
||||
mov dword ptr pos_src, esi
|
||||
shr esi, 16
|
||||
dec ecx
|
||||
jns short loop_stereo
|
||||
|
||||
mov CD_Audio_Buffer_Write_Pos, edi
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov edi, CD_Audio_Buffer_Write_Pos
|
||||
mov ebx, Buf
|
||||
xor esi, esi
|
||||
mov ecx, lenght_dst
|
||||
xor eax, eax
|
||||
mov edx, pas_src
|
||||
dec ecx
|
||||
jmp short loop_mono
|
||||
|
||||
align 16
|
||||
|
||||
loop_mono:
|
||||
movsx eax, word ptr [ebx + esi * 2]
|
||||
mov CD_Audio_Buffer_L[edi * 4], eax
|
||||
mov CD_Audio_Buffer_R[edi * 4], eax
|
||||
mov esi, dword ptr pos_src
|
||||
inc edi
|
||||
add esi, edx
|
||||
and edi, 0xFFF
|
||||
mov dword ptr pos_src, esi
|
||||
shr esi, 16
|
||||
dec ecx
|
||||
jns short loop_mono
|
||||
|
||||
mov CD_Audio_Buffer_Write_Pos, edi
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
fprintf(debug_SCD_file, "Write Pos 2 = %d\n\n", CD_Audio_Buffer_Write_Pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Update_CD_Audio(int **buf, int lenght)
|
||||
{
|
||||
int *Buf_L, *Buf_R;
|
||||
int diff;
|
||||
|
||||
Buf_L = buf[0];
|
||||
Buf_R = buf[1];
|
||||
|
||||
if (Pico_mcd->s68k_regs[0x36] & 0x01) return;
|
||||
if (!(Pico_mcd->scd.Status_CDC & 1)) return;
|
||||
if (CD_Audio_Starting) return;
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
fprintf(debug_SCD_file, "\n********* Read Pos Normal = %d ", CD_Audio_Buffer_Read_Pos);
|
||||
#endif
|
||||
|
||||
if (CD_Audio_Buffer_Write_Pos < CD_Audio_Buffer_Read_Pos)
|
||||
{
|
||||
diff = CD_Audio_Buffer_Write_Pos + (4096) - CD_Audio_Buffer_Read_Pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = CD_Audio_Buffer_Write_Pos - CD_Audio_Buffer_Read_Pos;
|
||||
}
|
||||
|
||||
if (diff < 500) CD_Audio_Buffer_Read_Pos -= 2000;
|
||||
else if (diff > 3500) CD_Audio_Buffer_Read_Pos += 2000;
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
else fprintf(debug_SCD_file, " pas de modifs ");
|
||||
#endif
|
||||
|
||||
CD_Audio_Buffer_Read_Pos &= 0xFFF;
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
fprintf(debug_SCD_file, "Read Pos = %d ", CD_Audio_Buffer_Read_Pos);
|
||||
#endif
|
||||
|
||||
if (CDDA_Enable)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov ecx, lenght
|
||||
mov esi, CD_Audio_Buffer_Read_Pos
|
||||
mov edi, Buf_L
|
||||
dec ecx
|
||||
|
||||
loop_L:
|
||||
mov eax, CD_Audio_Buffer_L[esi * 4]
|
||||
add [edi], eax
|
||||
inc esi
|
||||
add edi, 4
|
||||
and esi, 0xFFF
|
||||
dec ecx
|
||||
jns short loop_L
|
||||
|
||||
mov ecx, lenght
|
||||
mov esi, CD_Audio_Buffer_Read_Pos
|
||||
mov edi, Buf_R
|
||||
dec ecx
|
||||
|
||||
loop_R:
|
||||
mov eax, CD_Audio_Buffer_R[esi * 4]
|
||||
add [edi], eax
|
||||
inc esi
|
||||
add edi, 4
|
||||
and esi, 0xFFF
|
||||
dec ecx
|
||||
jns short loop_R
|
||||
|
||||
mov CD_Audio_Buffer_Read_Pos, esi
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CD_Audio_Buffer_Read_Pos += lenght;
|
||||
CD_Audio_Buffer_Read_Pos &= 0xFFF;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CD
|
||||
fprintf(debug_SCD_file, "Read Pos 2 = %d\n\n", CD_Audio_Buffer_Read_Pos);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
97
Pico/cd/cd_sys.h
Normal file
97
Pico/cd/cd_sys.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef _CD_SYS_H
|
||||
#define _CD_SYS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define INT_TO_BCDB(c) \
|
||||
((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10));
|
||||
|
||||
#define INT_TO_BCDW(c) \
|
||||
((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10));
|
||||
|
||||
#define BCDB_TO_INT(c) \
|
||||
(((c) >> 4) * 10) + ((c) & 0xF);
|
||||
|
||||
#define BCDW_TO_INT(c) \
|
||||
(((c) >> 8) * 10) + ((c) & 0xF);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char M;
|
||||
unsigned char S;
|
||||
unsigned char F;
|
||||
} _msf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char Type;
|
||||
unsigned char Num;
|
||||
_msf MSF;
|
||||
} _scd_track;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char First_Track;
|
||||
unsigned char Last_Track;
|
||||
_scd_track Tracks[100];
|
||||
} _scd_toc;
|
||||
|
||||
typedef struct {
|
||||
unsigned int Status_CDD;
|
||||
unsigned int Status_CDC;
|
||||
_scd_toc TOC;
|
||||
int Cur_LBA;
|
||||
unsigned int Cur_Track;
|
||||
} _scd;
|
||||
|
||||
|
||||
extern int CD_Timer_Counter;
|
||||
|
||||
|
||||
void LBA_to_MSF(int lba, _msf *MSF);
|
||||
int Track_to_LBA(int track);
|
||||
|
||||
|
||||
void Check_CD_Command(void);
|
||||
|
||||
int Init_CD_Driver(void);
|
||||
void End_CD_Driver(void);
|
||||
int Insert_CD(char *buf, char *iso_name);
|
||||
void Stop_CD(void);
|
||||
void Change_CD(void);
|
||||
void Reset_CD(void);
|
||||
|
||||
int Get_Status_CDD_c0(void);
|
||||
int Stop_CDD_c1(void);
|
||||
int Get_Pos_CDD_c20(void);
|
||||
int Get_Track_Pos_CDD_c21(void);
|
||||
int Get_Current_Track_CDD_c22(void);
|
||||
int Get_Total_Lenght_CDD_c23(void);
|
||||
int Get_First_Last_Track_CDD_c24(void);
|
||||
int Get_Track_Adr_CDD_c25(void);
|
||||
int Play_CDD_c3(void);
|
||||
int Seek_CDD_c4(void);
|
||||
int Pause_CDD_c6(void);
|
||||
int Resume_CDD_c7(void);
|
||||
int Fast_Foward_CDD_c8(void);
|
||||
int Fast_Rewind_CDD_c9(void);
|
||||
int CDD_cA(void);
|
||||
int Close_Tray_CDD_cC(void);
|
||||
int Open_Tray_CDD_cD(void);
|
||||
|
||||
int CDD_Def(void);
|
||||
|
||||
//void Write_CD_Audio(short *Buf, int rate, int channel, int lenght);
|
||||
//void Update_CD_Audio(int **Buf, int lenght);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
347
Pico/sound/sn76496.c
Normal file
347
Pico/sound/sn76496.c
Normal file
|
@ -0,0 +1,347 @@
|
|||
/***************************************************************************
|
||||
|
||||
sn76496.c
|
||||
|
||||
Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
|
||||
tone /noise generator. Also known as (or at least compatible with) TMS9919.
|
||||
|
||||
Noise emulation is not accurate due to lack of documentation. The noise
|
||||
generator uses a shift register with a XOR-feedback network, but the exact
|
||||
layout is unknown. It can be set for either period or white noise; again,
|
||||
the details are unknown.
|
||||
|
||||
28/03/2005 : Sebastien Chevalier
|
||||
Update th SN76496Write func, according to SN76489 doc found on SMSPower.
|
||||
- On write with 0x80 set to 0, when LastRegister is other then TONE,
|
||||
the function is similar than update with 0x80 set to 1
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __GNUC__
|
||||
#pragma warning (disable:4244)
|
||||
#endif
|
||||
|
||||
#include "sn76496.h"
|
||||
|
||||
#define MAX_OUTPUT 0x47ff // was 0x7fff
|
||||
|
||||
#define STEP 0x10000
|
||||
|
||||
|
||||
/* Formulas for noise generator */
|
||||
/* bit0 = output */
|
||||
|
||||
/* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */
|
||||
#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */
|
||||
|
||||
/* noise feedback for periodic noise mode */
|
||||
//#define FB_PNOISE 0x10000 /* 16bit rorate */
|
||||
#define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */
|
||||
|
||||
/*
|
||||
0x08000 is definitely wrong. The Master System conversion of Marble Madness
|
||||
uses periodic noise as a baseline. With a 15-bit rotate, the bassline is
|
||||
out of tune.
|
||||
The 16-bit rotate has been confirmed against a real PAL Sega Master System 2.
|
||||
Hope that helps the System E stuff, more news on the PSG as and when!
|
||||
*/
|
||||
|
||||
/* noise generator start preset (for periodic noise) */
|
||||
#define NG_PRESET 0x0f35
|
||||
|
||||
|
||||
struct SN76496
|
||||
{
|
||||
//sound_stream * Channel;
|
||||
int SampleRate;
|
||||
unsigned int UpdateStep;
|
||||
int VolTable[16]; /* volume table */
|
||||
int Register[8]; /* registers */
|
||||
int LastRegister; /* last register written */
|
||||
int Volume[4]; /* volume of voice 0-2 and noise */
|
||||
unsigned int RNG; /* noise generator */
|
||||
int NoiseFB; /* noise feedback mask */
|
||||
int Period[4];
|
||||
int Count[4];
|
||||
int Output[4];
|
||||
int pad[1];
|
||||
};
|
||||
|
||||
static struct SN76496 ono_sn; // one and only SN76496
|
||||
int *sn76496_regs;
|
||||
|
||||
//static
|
||||
void SN76496Write(int data)
|
||||
{
|
||||
struct SN76496 *R = &ono_sn;
|
||||
int n;
|
||||
|
||||
|
||||
/* update the output buffer before changing the registers */
|
||||
//stream_update(R->Channel,0);
|
||||
|
||||
if (data & 0x80)
|
||||
{
|
||||
int r = (data & 0x70) >> 4;
|
||||
int c = r/2;
|
||||
|
||||
R->LastRegister = r;
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
case 1: /* tone 0 : volume */
|
||||
case 3: /* tone 1 : volume */
|
||||
case 5: /* tone 2 : volume */
|
||||
case 7: /* noise : volume */
|
||||
R->Volume[c] = R->VolTable[data & 0x0f];
|
||||
break;
|
||||
case 6: /* noise : frequency, mode */
|
||||
{
|
||||
int n = R->Register[6];
|
||||
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
|
||||
n &= 3;
|
||||
/* N/512,N/1024,N/2048,Tone #3 output */
|
||||
R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3)));
|
||||
|
||||
/* reset noise shifter */
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = R->LastRegister;
|
||||
int c = r/2;
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
case 1: /* tone 0 : volume */
|
||||
case 3: /* tone 1 : volume */
|
||||
case 5: /* tone 2 : volume */
|
||||
case 7: /* noise : volume */
|
||||
R->Volume[c] = R->VolTable[data & 0x0f];
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
break;
|
||||
case 6: /* noise : frequency, mode */
|
||||
{
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
n = R->Register[6];
|
||||
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
|
||||
n &= 3;
|
||||
/* N/512,N/1024,N/2048,Tone #3 output */
|
||||
R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3)));
|
||||
|
||||
/* reset noise shifter */
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
WRITE8_HANDLER( SN76496_0_w ) { SN76496Write(0,data); }
|
||||
WRITE8_HANDLER( SN76496_1_w ) { SN76496Write(1,data); }
|
||||
WRITE8_HANDLER( SN76496_2_w ) { SN76496Write(2,data); }
|
||||
WRITE8_HANDLER( SN76496_3_w ) { SN76496Write(3,data); }
|
||||
WRITE8_HANDLER( SN76496_4_w ) { SN76496Write(4,data); }
|
||||
*/
|
||||
|
||||
//static
|
||||
void SN76496Update(short *buffer,int length,int stereo)
|
||||
{
|
||||
int i;
|
||||
struct SN76496 *R = &ono_sn;
|
||||
|
||||
/* If the volume is 0, increase the counter */
|
||||
for (i = 0;i < 4;i++)
|
||||
{
|
||||
if (R->Volume[i] == 0)
|
||||
{
|
||||
/* note that I do count += length, NOT count = length + 1. You might think */
|
||||
/* it's the same since the volume is 0, but doing the latter could cause */
|
||||
/* interferencies when the program is rapidly modulating the volume. */
|
||||
if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
|
||||
}
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int vol[4];
|
||||
unsigned int out;
|
||||
int left;
|
||||
|
||||
|
||||
/* vol[] keeps track of how long each square wave stays */
|
||||
/* in the 1 position during the sample period. */
|
||||
vol[0] = vol[1] = vol[2] = vol[3] = 0;
|
||||
|
||||
for (i = 0;i < 3;i++)
|
||||
{
|
||||
if (R->Output[i]) vol[i] += R->Count[i];
|
||||
R->Count[i] -= STEP;
|
||||
/* Period[i] is the half period of the square wave. Here, in each */
|
||||
/* loop I add Period[i] twice, so that at the end of the loop the */
|
||||
/* square wave is in the same status (0 or 1) it was at the start. */
|
||||
/* vol[i] is also incremented by Period[i], since the wave has been 1 */
|
||||
/* exactly half of the time, regardless of the initial position. */
|
||||
/* If we exit the loop in the middle, Output[i] has to be inverted */
|
||||
/* and vol[i] incremented only if the exit status of the square */
|
||||
/* wave is 1. */
|
||||
while (R->Count[i] <= 0)
|
||||
{
|
||||
R->Count[i] += R->Period[i];
|
||||
if (R->Count[i] > 0)
|
||||
{
|
||||
R->Output[i] ^= 1;
|
||||
if (R->Output[i]) vol[i] += R->Period[i];
|
||||
break;
|
||||
}
|
||||
R->Count[i] += R->Period[i];
|
||||
vol[i] += R->Period[i];
|
||||
}
|
||||
if (R->Output[i]) vol[i] -= R->Count[i];
|
||||
}
|
||||
|
||||
left = STEP;
|
||||
do
|
||||
{
|
||||
int nextevent;
|
||||
|
||||
if (R->Count[3] < left) nextevent = R->Count[3];
|
||||
else nextevent = left;
|
||||
|
||||
if (R->Output[3]) vol[3] += R->Count[3];
|
||||
R->Count[3] -= nextevent;
|
||||
if (R->Count[3] <= 0)
|
||||
{
|
||||
if (R->RNG & 1) R->RNG ^= R->NoiseFB;
|
||||
R->RNG >>= 1;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
R->Count[3] += R->Period[3];
|
||||
if (R->Output[3]) vol[3] += R->Period[3];
|
||||
}
|
||||
if (R->Output[3]) vol[3] -= R->Count[3];
|
||||
|
||||
left -= nextevent;
|
||||
} while (left > 0);
|
||||
|
||||
out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
|
||||
vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
|
||||
|
||||
if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
|
||||
|
||||
out /= STEP; // will be optimized to shift
|
||||
if(stereo) {
|
||||
// only left channel for stereo (will be copied to right by ym2612 mixing code)
|
||||
*buffer += out;
|
||||
buffer+=2;
|
||||
} else
|
||||
*buffer++ += out;
|
||||
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void SN76496_set_clock(struct SN76496 *R,int clock)
|
||||
{
|
||||
|
||||
/* the base clock for the tone generators is the chip clock divided by 16; */
|
||||
/* for the noise generator, it is clock / 256. */
|
||||
/* Here we calculate the number of steps which happen during one sample */
|
||||
/* at the given sample rate. No. of events = sample rate / (clock/16). */
|
||||
/* STEP is a multiplier used to turn the fraction into a fixed point */
|
||||
/* number. */
|
||||
R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
|
||||
}
|
||||
|
||||
|
||||
static void SN76496_set_gain(struct SN76496 *R,int gain)
|
||||
{
|
||||
int i;
|
||||
double out;
|
||||
|
||||
|
||||
gain &= 0xff;
|
||||
|
||||
/* increase max output basing on gain (0.2 dB per step) */
|
||||
out = MAX_OUTPUT / 3;
|
||||
while (gain-- > 0)
|
||||
out *= 1.023292992; /* = (10 ^ (0.2/20)) */
|
||||
|
||||
/* build volume table (2dB per step) */
|
||||
for (i = 0;i < 15;i++)
|
||||
{
|
||||
/* limit volume to avoid clipping */
|
||||
if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
|
||||
else R->VolTable[i] = out;
|
||||
|
||||
out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
|
||||
}
|
||||
R->VolTable[15] = 0;
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
int SN76496_init(int clock,int sample_rate)
|
||||
{
|
||||
struct SN76496 *R = &ono_sn;
|
||||
int i;
|
||||
|
||||
//R->Channel = stream_create(0,1, sample_rate,R,SN76496Update);
|
||||
sn76496_regs = R->Register;
|
||||
|
||||
R->SampleRate = sample_rate;
|
||||
SN76496_set_clock(R,clock);
|
||||
|
||||
for (i = 0;i < 4;i++) R->Volume[i] = 0;
|
||||
|
||||
R->LastRegister = 0;
|
||||
for (i = 0;i < 8;i+=2)
|
||||
{
|
||||
R->Register[i] = 0;
|
||||
R->Register[i + 1] = 0x0f; /* volume = 0 */
|
||||
}
|
||||
|
||||
for (i = 0;i < 4;i++)
|
||||
{
|
||||
R->Output[i] = 0;
|
||||
R->Period[i] = R->Count[i] = R->UpdateStep;
|
||||
}
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
|
||||
// added
|
||||
SN76496_set_gain(R, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
8
Pico/sound/sn76496.h
Normal file
8
Pico/sound/sn76496.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef SN76496_H
|
||||
#define SN76496_H
|
||||
|
||||
void SN76496Write(int data);
|
||||
void SN76496Update(short *buffer,int length,int stereo);
|
||||
int SN76496_init(int clock,int sample_rate);
|
||||
|
||||
#endif
|
390
Pico/sound/sound.c
Normal file
390
Pico/sound/sound.c
Normal file
|
@ -0,0 +1,390 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "sound.h"
|
||||
#include "ym2612.h"
|
||||
#include "sn76496.h"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#pragma warning (disable:4244)
|
||||
#endif
|
||||
|
||||
#if defined(_USE_MZ80)
|
||||
#include "../../cpu/mz80/mz80.h"
|
||||
#elif defined(_USE_DRZ80)
|
||||
#include "../../cpu/DrZ80/drz80.h"
|
||||
#endif
|
||||
|
||||
#include "../PicoInt.h"
|
||||
|
||||
|
||||
//int z80CycleAim = 0;
|
||||
|
||||
// dac
|
||||
short *dac_out;
|
||||
unsigned short dac_info[312]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample
|
||||
|
||||
// for Pico
|
||||
int PsndRate=0;
|
||||
int PsndLen=0; // number of mono samples, multiply by 2 for stereo
|
||||
short *PsndOut=NULL; // PCM data buffer
|
||||
|
||||
// from ym2612.c
|
||||
extern int *ym2612_dacen;
|
||||
extern INT32 *ym2612_dacout;
|
||||
void YM2612TimerHandler(int c,int cnt);
|
||||
|
||||
// sn76496
|
||||
extern int *sn76496_regs;
|
||||
|
||||
|
||||
static void dac_recalculate()
|
||||
{
|
||||
int i, dac_cnt, pos, len, lines = Pico.m.pal ? 312 : 262, mid = Pico.m.pal ? 68 : 93;
|
||||
|
||||
if(PsndLen <= lines) {
|
||||
// shrinking algo
|
||||
dac_cnt = 0;//lines - PsndLen;
|
||||
len=1; pos=0;
|
||||
dac_info[225] = 1;
|
||||
|
||||
for(i=226; i != 225; i++) {
|
||||
if (i >= lines) i = 0;
|
||||
len = 0;
|
||||
if(dac_cnt < 0) {
|
||||
len=1;
|
||||
pos++;
|
||||
dac_cnt += lines;
|
||||
}
|
||||
dac_cnt -= PsndLen;
|
||||
dac_info[i] = (pos<<4)|len;
|
||||
}
|
||||
} else {
|
||||
// stretching
|
||||
dac_cnt = PsndLen/2;
|
||||
pos=0;
|
||||
for(i = 225; i != 224; i++) {
|
||||
if (i >= lines) i = 0;
|
||||
len=0;
|
||||
while(dac_cnt >= 0) {
|
||||
dac_cnt -= lines;
|
||||
len++;
|
||||
}
|
||||
if (i == mid) // midpoint
|
||||
while(pos+len < PsndLen/2) {
|
||||
dac_cnt -= lines;
|
||||
len++;
|
||||
}
|
||||
dac_cnt += PsndLen;
|
||||
dac_info[i] = (pos<<4)|len;
|
||||
pos+=len;
|
||||
}
|
||||
// last sample
|
||||
for(len = 0, i = pos; i < PsndLen; i++) len++;
|
||||
dac_info[224] = (pos<<4)|len;
|
||||
}
|
||||
// dprintf("rate is %i, len %i", PsndRate, PsndLen);
|
||||
// for(i=0; i < lines; i++)
|
||||
// dprintf("%03i : %03i : %i", i, dac_info[i]>>4, dac_info[i]&0xf);
|
||||
//exit(8);
|
||||
}
|
||||
|
||||
|
||||
void sound_reset()
|
||||
{
|
||||
extern int z80stopCycle;
|
||||
void *ym2612_regs;
|
||||
|
||||
// init even if we are not going to use them, just in case we ever enable it
|
||||
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);
|
||||
// also clear the internal registers+addr line
|
||||
ym2612_regs = YM2612GetRegs();
|
||||
memset(ym2612_regs, 0, 0x200+4);
|
||||
|
||||
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate);
|
||||
|
||||
// calculate PsndLen
|
||||
PsndLen=PsndRate/(Pico.m.pal ? 50 : 60);
|
||||
|
||||
// recalculate dac info
|
||||
dac_recalculate();
|
||||
z80stopCycle = 0;
|
||||
}
|
||||
|
||||
|
||||
// to be called after changing sound rate or chips
|
||||
void sound_rerate()
|
||||
{
|
||||
unsigned int state[28];
|
||||
|
||||
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);
|
||||
// feed it back it's own registers, just like after loading state
|
||||
YM2612PicoStateLoad();
|
||||
|
||||
memcpy(state, sn76496_regs, 28*4); // remember old state
|
||||
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate);
|
||||
memcpy(sn76496_regs, state, 28*4); // restore old state
|
||||
|
||||
// calculate PsndLen
|
||||
PsndLen=PsndRate/(Pico.m.pal ? 50 : 60);
|
||||
|
||||
// recalculate dac info
|
||||
dac_recalculate();
|
||||
}
|
||||
|
||||
|
||||
// This is called once per raster (aka line), but not necessarily for every line
|
||||
int sound_timers_and_dac(int raster)
|
||||
{
|
||||
if(raster >= 0 && PsndOut && (PicoOpt&1) && *ym2612_dacen) {
|
||||
short dout = (short) *ym2612_dacout;
|
||||
int pos=dac_info[raster], len=pos&0xf;
|
||||
short *d;
|
||||
pos>>=4;
|
||||
|
||||
if(PicoOpt&8) { // only left channel for stereo (will be copied to right by ym2612 mixing code)
|
||||
d=PsndOut+pos*2;
|
||||
while(len--) { *d = dout; d += 2; }
|
||||
} else {
|
||||
d=PsndOut+pos;
|
||||
while(len--) *d++ = dout;
|
||||
}
|
||||
}
|
||||
|
||||
//dprintf("s: %03i", raster);
|
||||
|
||||
// Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)
|
||||
YM2612PicoTick(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sound_render(int offset, int length)
|
||||
{
|
||||
int stereo = (PicoOpt & 8) >> 3;
|
||||
offset <<= stereo;
|
||||
|
||||
// PSG
|
||||
if(PicoOpt & 2)
|
||||
SN76496Update(PsndOut+offset, length, stereo);
|
||||
|
||||
// Add in the stereo FM buffer
|
||||
if(PicoOpt & 1) {
|
||||
YM2612UpdateOne(PsndOut+offset, length, stereo);
|
||||
} else {
|
||||
// YM2612 upmixes to stereo, so we have to do this manually here
|
||||
int i;
|
||||
short *s = PsndOut+offset;
|
||||
for (i = 0; i < length; i++) {
|
||||
*(s+1) = *s; s+=2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(_USE_MZ80)
|
||||
|
||||
// memhandlers for mz80 core
|
||||
unsigned char mz80_read(UINT32 a, struct MemoryReadByte *w) { return z80_read(a); }
|
||||
void mz80_write(UINT32 a, UINT8 d, struct MemoryWriteByte *w) { z80_write(d, a); }
|
||||
|
||||
// structures for mz80 core
|
||||
static struct MemoryReadByte mz80_mem_read[]=
|
||||
{
|
||||
{0x0000,0xffff,mz80_read},
|
||||
{(UINT32) -1,(UINT32) -1,NULL}
|
||||
};
|
||||
static struct MemoryWriteByte mz80_mem_write[]=
|
||||
{
|
||||
{0x0000,0xffff,mz80_write},
|
||||
{(UINT32) -1,(UINT32) -1,NULL}
|
||||
};
|
||||
static struct z80PortRead mz80_io_read[] ={
|
||||
{(UINT16) -1,(UINT16) -1,NULL}
|
||||
};
|
||||
static struct z80PortWrite mz80_io_write[]={
|
||||
{(UINT16) -1,(UINT16) -1,NULL}
|
||||
};
|
||||
|
||||
#elif defined(_USE_DRZ80)
|
||||
|
||||
static struct DrZ80 drZ80;
|
||||
|
||||
static unsigned int DrZ80_rebasePC(unsigned short a)
|
||||
{
|
||||
drZ80.Z80PC_BASE = (unsigned int) Pico.zram;
|
||||
return drZ80.Z80PC_BASE + a;
|
||||
}
|
||||
|
||||
static unsigned int DrZ80_rebaseSP(unsigned short a)
|
||||
{
|
||||
drZ80.Z80SP_BASE = (unsigned int) Pico.zram;
|
||||
return drZ80.Z80SP_BASE + a;
|
||||
}
|
||||
|
||||
static unsigned char DrZ80_in(unsigned short p)
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void DrZ80_out(unsigned short p,unsigned char d)
|
||||
{
|
||||
}
|
||||
|
||||
static void DrZ80_irq_callback()
|
||||
{
|
||||
drZ80.Z80_IRQ = 0; // lower irq when accepted
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// z80 functionality wrappers
|
||||
void z80_init()
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
struct mz80context z80;
|
||||
|
||||
// z80
|
||||
mz80init();
|
||||
// Modify the default context
|
||||
mz80GetContext(&z80);
|
||||
|
||||
// point mz80 stuff
|
||||
z80.z80Base=Pico.zram;
|
||||
z80.z80MemRead=mz80_mem_read;
|
||||
z80.z80MemWrite=mz80_mem_write;
|
||||
z80.z80IoRead=mz80_io_read;
|
||||
z80.z80IoWrite=mz80_io_write;
|
||||
|
||||
mz80SetContext(&z80);
|
||||
|
||||
#elif defined(_USE_DRZ80)
|
||||
|
||||
memset(&drZ80, 0, sizeof(struct DrZ80));
|
||||
drZ80.z80_rebasePC=DrZ80_rebasePC;
|
||||
drZ80.z80_rebaseSP=DrZ80_rebaseSP;
|
||||
drZ80.z80_read8 =z80_read;
|
||||
drZ80.z80_read16 =z80_read16;
|
||||
drZ80.z80_write8 =z80_write;
|
||||
drZ80.z80_write16 =z80_write16;
|
||||
drZ80.z80_in =DrZ80_in;
|
||||
drZ80.z80_out =DrZ80_out;
|
||||
drZ80.z80_irq_callback=DrZ80_irq_callback;
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_reset()
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
mz80reset();
|
||||
#elif defined(_USE_DRZ80)
|
||||
memset(&drZ80, 0, 0x54);
|
||||
drZ80.Z80F = (1<<2); // set ZFlag
|
||||
drZ80.Z80F2 = (1<<2); // set ZFlag
|
||||
drZ80.Z80IX = 0xFFFF << 16;
|
||||
drZ80.Z80IY = 0xFFFF << 16;
|
||||
drZ80.Z80IM = 0; // 1?
|
||||
drZ80.Z80PC = drZ80.z80_rebasePC(0);
|
||||
drZ80.Z80SP = drZ80.z80_rebaseSP(0x2000); // 0xf000 ?
|
||||
#endif
|
||||
Pico.m.z80_fakeval = 0; // for faking when Z80 is disabled
|
||||
}
|
||||
|
||||
void z80_resetCycles()
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
mz80GetElapsedTicks(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_int()
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
mz80int(0);
|
||||
#elif defined(_USE_DRZ80)
|
||||
drZ80.z80irqvector = 0xFF; // default IRQ vector RST opcode
|
||||
drZ80.Z80_IRQ = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns number of cycles actually executed
|
||||
int z80_run(int cycles)
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
int ticks_pre = mz80GetElapsedTicks(0);
|
||||
mz80exec(cycles);
|
||||
return mz80GetElapsedTicks(0) - ticks_pre;
|
||||
#elif defined(_USE_DRZ80)
|
||||
return cycles - DrZ80Run(&drZ80, cycles);
|
||||
#else
|
||||
return cycles;
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_pack(unsigned char *data)
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
struct mz80context mz80;
|
||||
*(int *)data = 0x00005A6D; // "mZ"
|
||||
mz80GetContext(&mz80);
|
||||
memcpy(data+4, &mz80.z80clockticks, sizeof(mz80)-5*4); // don't save base&memhandlers
|
||||
#elif defined(_USE_DRZ80)
|
||||
*(int *)data = 0x015A7244; // "DrZ" v1
|
||||
drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE);
|
||||
drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE);
|
||||
memcpy(data+4, &drZ80, 0x54);
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_unpack(unsigned char *data)
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
if(*(int *)data == 0x00005A6D) { // "mZ" save?
|
||||
struct mz80context mz80;
|
||||
mz80GetContext(&mz80);
|
||||
memcpy(&mz80.z80clockticks, data+4, sizeof(mz80)-5*4);
|
||||
mz80SetContext(&mz80);
|
||||
} else {
|
||||
z80_reset();
|
||||
z80_int();
|
||||
}
|
||||
#elif defined(_USE_DRZ80)
|
||||
if(*(int *)data == 0x015A7244) { // "DrZ" v1 save?
|
||||
memcpy(&drZ80, data+4, 0x54);
|
||||
// update bases
|
||||
drZ80.Z80PC = drZ80.z80_rebasePC(drZ80.Z80PC-drZ80.Z80PC_BASE);
|
||||
drZ80.Z80SP = drZ80.z80_rebaseSP(drZ80.Z80SP-drZ80.Z80SP_BASE);
|
||||
} else {
|
||||
z80_reset();
|
||||
drZ80.Z80IM = 1;
|
||||
z80_int(); // try to goto int handler, maybe we won't execute trash there?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void z80_exit()
|
||||
{
|
||||
#if defined(_USE_MZ80)
|
||||
mz80shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__DEBUG_PRINT) || defined(WIN32)
|
||||
void z80_debug(char *dstr)
|
||||
{
|
||||
#if defined(_USE_DRZ80)
|
||||
sprintf(dstr, "%sZ80 state: PC: %04x SP: %04x\n", dstr, drZ80.Z80PC-drZ80.Z80PC_BASE, drZ80.Z80SP-drZ80.Z80SP_BASE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
28
Pico/sound/sound.h
Normal file
28
Pico/sound/sound.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// This is part of Pico Library
|
||||
|
||||
// (c) Copyright 2004 Dave, All rights reserved.
|
||||
// (c) Copyright 2006 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int sound_timers_and_dac(int raster);
|
||||
int sound_render(int offset, int length);
|
||||
|
||||
//int YM2612PicoTick(int n);
|
||||
|
||||
// z80 functionality wrappers
|
||||
void z80_init();
|
||||
void z80_resetCycles();
|
||||
void z80_int();
|
||||
int z80_run(int cycles);
|
||||
void z80_exit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // End of extern "C"
|
||||
#endif
|
1899
Pico/sound/ym2612.c
Normal file
1899
Pico/sound/ym2612.c
Normal file
File diff suppressed because it is too large
Load diff
192
Pico/sound/ym2612.h
Normal file
192
Pico/sound/ym2612.h
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
header file for software emulation for FM sound generator
|
||||
|
||||
*/
|
||||
#ifndef _H_FM_FM_
|
||||
#define _H_FM_FM_
|
||||
|
||||
/* compiler dependence */
|
||||
#ifndef UINT8
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
#endif
|
||||
#ifndef INT8
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
/* struct describing a single operator (SLOT) */
|
||||
typedef struct
|
||||
{
|
||||
INT32 *DT; /* #0x00 detune :dt_tab[DT] */
|
||||
UINT8 ar; /* #0x04 attack rate */
|
||||
UINT8 d1r; /* #0x05 decay rate */
|
||||
UINT8 d2r; /* #0x06 sustain rate */
|
||||
UINT8 rr; /* #0x07 release rate */
|
||||
UINT32 mul; /* #0x08 multiple :ML_TABLE[ML] */
|
||||
|
||||
/* Phase Generator */
|
||||
UINT32 phase; /* #0x0c phase counter */
|
||||
UINT32 Incr; /* #0x10 phase step */
|
||||
|
||||
UINT8 KSR; /* #0x14 key scale rate :3-KSR */
|
||||
UINT8 ksr; /* #0x15 key scale rate :kcode>>(3-KSR) */
|
||||
|
||||
UINT8 key; /* #0x16 0=last key was KEY OFF, 1=KEY ON */
|
||||
|
||||
/* Envelope Generator */
|
||||
UINT8 state; /* #0x17 phase type: EG_OFF=0, EG_REL, EG_SUS, EG_DEC, EG_ATT */
|
||||
UINT16 tl; /* #0x18 total level: TL << 3 */
|
||||
INT16 volume; /* #0x1a envelope counter */
|
||||
UINT32 sl; /* #0x1c sustain level:sl_table[SL] */
|
||||
|
||||
UINT32 eg_pack_ar; /* #0x20 (attack state) */
|
||||
UINT32 eg_pack_d1r; /* #0x24 (decay state) */
|
||||
UINT32 eg_pack_d2r; /* #0x28 (sustain state) */
|
||||
UINT32 eg_pack_rr; /* #0x2c (release state) */
|
||||
} FM_SLOT;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FM_SLOT SLOT[4]; /* four SLOTs (operators) */
|
||||
|
||||
UINT8 ALGO; /* algorithm */
|
||||
UINT8 FB; /* feedback shift */
|
||||
INT32 op1_out; /* op1 output for feedback */
|
||||
|
||||
INT32 mem_value; /* delayed sample (MEM) value */
|
||||
|
||||
INT32 pms; /* channel PMS */
|
||||
UINT8 ams; /* channel AMS */
|
||||
|
||||
UINT8 kcode; /* key code: */
|
||||
UINT32 fc; /* fnum,blk:adjusted to sample rate */
|
||||
UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
|
||||
|
||||
/* LFO */
|
||||
UINT8 AMmasks; /* AM enable flag */
|
||||
|
||||
} FM_CH;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int clock; /* master clock (Hz) */
|
||||
int rate; /* sampling rate (Hz) */
|
||||
double freqbase; /* frequency base */
|
||||
UINT8 address; /* address register */
|
||||
UINT8 status; /* status flag */
|
||||
UINT8 mode; /* mode CSM / 3SLOT */
|
||||
UINT8 fn_h; /* freq latch */
|
||||
int TA; /* timer a */
|
||||
int TAC; /* timer a maxval */
|
||||
int TAT; /* timer a ticker */
|
||||
UINT8 TB; /* timer b */
|
||||
int TBC; /* timer b maxval */
|
||||
int TBT; /* timer b ticker */
|
||||
/* local time tables */
|
||||
INT32 dt_tab[8][32];/* DeTune table */
|
||||
} FM_ST;
|
||||
|
||||
/***********************************************************/
|
||||
/* OPN unit */
|
||||
/***********************************************************/
|
||||
|
||||
/* OPN 3slot struct */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 fc[3]; /* fnum3,blk3: calculated */
|
||||
UINT8 fn_h; /* freq3 latch */
|
||||
UINT8 kcode[3]; /* key code */
|
||||
UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
|
||||
} FM_3SLOT;
|
||||
|
||||
/* OPN/A/B common state */
|
||||
typedef struct
|
||||
{
|
||||
FM_ST ST; /* general state */
|
||||
FM_3SLOT SL3; /* 3 slot mode state */
|
||||
UINT32 pan; /* fm channels output mask (bit 1 = enable) */
|
||||
|
||||
UINT32 eg_cnt; /* #0xb38 global envelope generator counter */
|
||||
UINT32 eg_timer; /* #0xb3c global envelope generator counter works at frequency = chipclock/64/3 */
|
||||
UINT32 eg_timer_add; /* #0xb40 step of eg_timer */
|
||||
|
||||
/* LFO */
|
||||
UINT32 lfo_cnt;
|
||||
UINT32 lfo_inc;
|
||||
|
||||
UINT32 lfo_freq[8]; /* LFO FREQ table */
|
||||
} FM_OPN;
|
||||
|
||||
/* here's the virtual YM2612 */
|
||||
typedef struct
|
||||
{
|
||||
UINT8 REGS[0x200]; /* registers (for save states) */
|
||||
INT32 addr_A1; /* address line A1 */
|
||||
|
||||
FM_CH CH[6]; /* channel state (0x168 bytes each)? */
|
||||
|
||||
/* dac output (YM2612) */
|
||||
int dacen;
|
||||
INT32 dacout;
|
||||
|
||||
FM_OPN OPN; /* OPN state */
|
||||
} YM2612;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void YM2612Init_(int baseclock, int rate);
|
||||
void YM2612ResetChip_(void);
|
||||
void YM2612UpdateOne_(short *buffer, int length, int stereo);
|
||||
|
||||
int YM2612Write_(unsigned int a, unsigned int v);
|
||||
unsigned char YM2612Read_(void);
|
||||
|
||||
int YM2612PicoTick_(int n);
|
||||
void YM2612PicoStateLoad_(void);
|
||||
|
||||
void *YM2612GetRegs(void);
|
||||
|
||||
#ifndef __GP2X__
|
||||
#define YM2612Init YM2612Init_
|
||||
#define YM2612ResetChip YM2612ResetChip_
|
||||
#define YM2612UpdateOne YM2612UpdateOne_
|
||||
#define YM2612Write YM2612Write_
|
||||
#define YM2612Read YM2612Read_
|
||||
#define YM2612PicoTick YM2612PicoTick_
|
||||
#define YM2612PicoStateLoad YM2612PicoStateLoad_
|
||||
#else
|
||||
/* GP2X specific */
|
||||
#include "../../platform/gp2x/940ctl_ym2612.h"
|
||||
extern int PicoOpt;
|
||||
#define YM2612Init(baseclock,rate) { \
|
||||
if (PicoOpt&0x200) YM2612Init_940(baseclock, rate); \
|
||||
else YM2612Init_(baseclock, rate); \
|
||||
}
|
||||
#define YM2612ResetChip() { \
|
||||
if (PicoOpt&0x200) YM2612ResetChip_940(); \
|
||||
else YM2612ResetChip_(); \
|
||||
}
|
||||
#define YM2612UpdateOne(buffer,length,stereo) { \
|
||||
if (PicoOpt&0x200) YM2612UpdateOne_940(buffer, length, stereo); \
|
||||
else YM2612UpdateOne_(buffer, length, stereo); \
|
||||
}
|
||||
#define YM2612Write(a,v) \
|
||||
(PicoOpt&0x200) ? YM2612Write_940(a, v) : YM2612Write_(a, v)
|
||||
#define YM2612Read() \
|
||||
(PicoOpt&0x200) ? YM2612Read_940() : YM2612Read_()
|
||||
#define YM2612PicoTick(n) \
|
||||
(PicoOpt&0x200) ? YM2612PicoTick_940(n) : YM2612PicoTick_(n)
|
||||
#define YM2612PicoStateLoad() { \
|
||||
if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \
|
||||
else YM2612PicoStateLoad_(); \
|
||||
}
|
||||
#endif /* __GP2X__ */
|
||||
|
||||
|
||||
#endif /* _H_FM_FM_ */
|
915
Pico/sound/ym2612.s
Normal file
915
Pico/sound/ym2612.s
Normal file
|
@ -0,0 +1,915 @@
|
|||
@ this is a rewrite of MAME's ym2612 code, in particular this is only the main sample-generatin loop.
|
||||
@ it does not seem to give much performance increase (if any at all), so don't use it if it causes trouble.
|
||||
@ - notaz, 2006
|
||||
|
||||
.equiv SLOT1, 0
|
||||
.equiv SLOT2, 2
|
||||
.equiv SLOT3, 1
|
||||
.equiv SLOT4, 3
|
||||
.equiv SLOT_STRUCT_SIZE, 0x30
|
||||
|
||||
.equiv TL_TAB_LEN, 0x1A00
|
||||
|
||||
.equiv EG_ATT, 4
|
||||
.equiv EG_DEC, 3
|
||||
.equiv EG_SUS, 2
|
||||
.equiv EG_REL, 1
|
||||
.equiv EG_OFF, 0
|
||||
|
||||
.equiv EG_SH, 16 @ 16.16 fixed point (envelope generator timing)
|
||||
.equiv EG_TIMER_OVERFLOW, (3*(1<<EG_SH)) @ envelope generator timer overflows every 3 samples (on real chip)
|
||||
.equiv LFO_SH, 25 /* 7.25 fixed point (LFO calculations) */
|
||||
|
||||
.equiv ENV_QUIET, (2*13*256/8)/2
|
||||
|
||||
|
||||
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
||||
@ writes output to routp, but only if vol_out changes
|
||||
.macro update_eg_phase_slot slot
|
||||
ldrb r2, [r5,#0x17] @ state
|
||||
mov r3, #1 @ 1ci
|
||||
cmp r2, #1
|
||||
blt 5f @ EG_OFF
|
||||
beq 3f @ EG_REL
|
||||
cmp r2, #3
|
||||
blt 2f @ EG_SUS
|
||||
beq 1f @ EG_DEC
|
||||
|
||||
0: @ EG_ATT
|
||||
ldr r2, [r5,#0x20] @ eg_pack_ar (1ci)
|
||||
mov r0, r2, lsr #24
|
||||
mov r3, r3, lsl r0
|
||||
sub r3, r3, #1
|
||||
tst r1, r3
|
||||
bne 5f @ do smth for tl problem (set on init?)
|
||||
mov r3, r1, lsr r0
|
||||
ldrh r0, [r5,#0x1a] @ volume, unsigned (0-1023)
|
||||
and r3, r3, #7
|
||||
add r3, r3, r3, lsl #1
|
||||
mov r3, r2, lsr r3
|
||||
and r3, r3, #7 @ shift for eg_inc calculation
|
||||
mvn r2, r0
|
||||
mov r2, r2, lsl r3
|
||||
add r0, r0, r2, asr #5
|
||||
cmp r0, #0 @ if (volume <= MIN_ATT_INDEX)
|
||||
movle r3, #EG_DEC
|
||||
strleb r3, [r5,#0x17] @ state
|
||||
movle r0, #0
|
||||
b 4f
|
||||
|
||||
1: @ EG_DEC
|
||||
ldr r2, [r5,#0x24] @ eg_pack_d1r (1ci)
|
||||
mov r0, r2, lsr #24
|
||||
mov r3, r3, lsl r0
|
||||
sub r3, r3, #1
|
||||
tst r1, r3
|
||||
bne 5f @ do smth for tl problem (set on init?)
|
||||
mov r3, r1, lsr r0
|
||||
ldrh r0, [r5,#0x1a] @ volume
|
||||
and r3, r3, #7
|
||||
add r3, r3, r3, lsl #1
|
||||
mov r3, r2, lsr r3
|
||||
and r3, r3, #7 @ shift for eg_inc calculation
|
||||
mov r2, #1
|
||||
mov r3, r2, lsl r3
|
||||
ldr r2, [r5,#0x1c] @ sl (can be 16bit?)
|
||||
add r0, r0, r3, asr #1
|
||||
cmp r0, r2 @ if ( volume >= (INT32) SLOT->sl )
|
||||
movge r3, #EG_SUS
|
||||
strgeb r3, [r5,#0x17] @ state
|
||||
b 4f
|
||||
|
||||
2: @ EG_SUS
|
||||
ldr r2, [r5,#0x28] @ eg_pack_d2r (1ci)
|
||||
mov r0, r2, lsr #24
|
||||
mov r3, r3, lsl r0
|
||||
sub r3, r3, #1
|
||||
tst r1, r3
|
||||
bne 5f @ do smth for tl problem (set on init?)
|
||||
mov r3, r1, lsr r0
|
||||
ldrh r0, [r5,#0x1a] @ volume
|
||||
and r3, r3, #7
|
||||
add r3, r3, r3, lsl #1
|
||||
mov r3, r2, lsr r3
|
||||
and r3, r3, #7 @ shift for eg_inc calculation
|
||||
mov r2, #1
|
||||
mov r3, r2, lsl r3
|
||||
add r0, r0, r3, asr #1
|
||||
mov r2, #1024
|
||||
sub r2, r2, #1 @ r2 = MAX_ATT_INDEX
|
||||
cmp r0, r2 @ if ( volume >= MAX_ATT_INDEX )
|
||||
movge r0, r2
|
||||
b 4f
|
||||
|
||||
3: @ EG_REL
|
||||
ldr r2, [r5,#0x2c] @ eg_pack_rr (1ci)
|
||||
mov r0, r2, lsr #24
|
||||
mov r3, r3, lsl r0
|
||||
sub r3, r3, #1
|
||||
tst r1, r3
|
||||
bne 5f @ do smth for tl problem (set on init?)
|
||||
mov r3, r1, lsr r0
|
||||
ldrh r0, [r5,#0x1a] @ volume
|
||||
and r3, r3, #7
|
||||
add r3, r3, r3, lsl #1
|
||||
mov r3, r2, lsr r3
|
||||
and r3, r3, #7 @ shift for eg_inc calculation
|
||||
mov r2, #1
|
||||
mov r3, r2, lsl r3
|
||||
add r0, r0, r3, asr #1
|
||||
mov r2, #1024
|
||||
sub r2, r2, #1 @ r2 = MAX_ATT_INDEX
|
||||
cmp r0, r2 @ if ( volume >= MAX_ATT_INDEX )
|
||||
movge r0, r2
|
||||
movge r3, #EG_OFF
|
||||
strgeb r3, [r5,#0x17] @ state
|
||||
|
||||
4:
|
||||
ldrh r3, [r5,#0x18] @ tl
|
||||
strh r0, [r5,#0x1a] @ volume
|
||||
.if \slot == SLOT1
|
||||
mov r6, r6, lsr #16
|
||||
add r0, r0, r3
|
||||
orr r6, r0, r6, lsl #16
|
||||
.elseif \slot == SLOT2
|
||||
mov r6, r6, lsl #16
|
||||
add r0, r0, r3
|
||||
mov r0, r0, lsl #16
|
||||
orr r6, r0, r6, lsr #16
|
||||
.elseif \slot == SLOT3
|
||||
mov r7, r7, lsr #16
|
||||
add r0, r0, r3
|
||||
orr r7, r0, r7, lsl #16
|
||||
.elseif \slot == SLOT4
|
||||
mov r7, r7, lsl #16
|
||||
add r0, r0, r3
|
||||
mov r0, r0, lsl #16
|
||||
orr r7, r0, r7, lsr #16
|
||||
.endif
|
||||
|
||||
5:
|
||||
.endm
|
||||
|
||||
|
||||
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch
|
||||
.macro advance_lfo_m
|
||||
mov r2, r2, lsr #LFO_SH
|
||||
cmp r2, r1, lsr #LFO_SH
|
||||
beq 0f
|
||||
and r3, r2, #0x3f
|
||||
cmp r2, #0x40
|
||||
rsbge r3, r3, #0x3f
|
||||
bic r12,r12, #0xff000000 @ lfo_ampm &= 0xff
|
||||
orr r12,r12, r3, lsl #1+24
|
||||
|
||||
mov r2, r2, lsr #2
|
||||
cmp r2, r1, lsr #LFO_SH+2
|
||||
bicne r12,r12, #0xff0000
|
||||
orrne r12,r12, r2, lsl #16
|
||||
|
||||
0:
|
||||
.endm
|
||||
|
||||
|
||||
@ result goes to r1, trashes r2
|
||||
.macro make_eg_out slot
|
||||
tst r12, #8
|
||||
tstne r12, #(1<<(\slot+8))
|
||||
.if \slot == SLOT1
|
||||
mov r1, r6, lsl #16
|
||||
mov r1, r1, lsr #17
|
||||
.elseif \slot == SLOT2
|
||||
mov r1, r6, lsr #17
|
||||
.elseif \slot == SLOT3
|
||||
mov r1, r7, lsl #16
|
||||
mov r1, r1, lsr #17
|
||||
.elseif \slot == SLOT4
|
||||
mov r1, r7, lsr #17
|
||||
.endif
|
||||
andne r2, r12, #0xc0
|
||||
movne r2, r2, lsr #6
|
||||
addne r2, r2, #24
|
||||
addne r1, r1, r12, lsr r2
|
||||
.endm
|
||||
|
||||
|
||||
.macro lookup_tl r
|
||||
tst \r, #0x100
|
||||
eorne \r, \r, #0xff @ if (sin & 0x100) sin = 0xff - (sin&0xff);
|
||||
tst \r, #0x200
|
||||
and \r, \r, #0xff
|
||||
orr \r, \r, r1, lsl #8
|
||||
mov \r, \r, lsl #1
|
||||
ldrh \r, [r3, \r] @ 2ci if ne
|
||||
rsbne \r, \r, #0
|
||||
.endm
|
||||
|
||||
|
||||
@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
|
||||
@ r0-r2=scratch, r3=sin_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
|
||||
.macro upd_algo0_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r2, [lr, #0x18]
|
||||
ldr r0, [lr, #0x38] @ mem (signed)
|
||||
mov r2, r2, lsr #16
|
||||
add r0, r2, r0, lsr #1
|
||||
lookup_tl r0 @ r0=c2
|
||||
|
||||
0:
|
||||
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r0, r0, lsr #1
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
1:
|
||||
@ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r2, #0
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14] @ 1ci
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2 @ r2=mem
|
||||
|
||||
2:
|
||||
str r2, [lr, #0x38] @ mem
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo1_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r2, [lr, #0x18]
|
||||
ldr r0, [lr, #0x38] @ mem (signed)
|
||||
mov r2, r2, lsr #16
|
||||
add r0, r2, r0, lsr #1
|
||||
lookup_tl r0 @ r0=c2
|
||||
|
||||
0:
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r0, r0, lsr #1
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
1:
|
||||
@ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r2, #0
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14] @ 1ci
|
||||
mov r2, r2, lsr #16
|
||||
lookup_tl r2 @ r2=mem
|
||||
|
||||
2:
|
||||
add r2, r2, r10, asr #16
|
||||
str r2, [lr, #0x38]
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo2_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r2, [lr, #0x18]
|
||||
ldr r0, [lr, #0x38] @ mem (signed)
|
||||
mov r2, r2, lsr #16
|
||||
add r0, r2, r0, lsr #1
|
||||
lookup_tl r0 @ r0=c2
|
||||
|
||||
0:
|
||||
add r0, r0, r10, asr #16
|
||||
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r0, r0, lsr #1
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
1:
|
||||
@ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r2, #0
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r2, r2, lsr #16 @ 1ci
|
||||
lookup_tl r2 @ r2=mem
|
||||
|
||||
2:
|
||||
str r2, [lr, #0x38] @ mem
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo3_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
ldr r2, [lr, #0x38] @ mem (for future)
|
||||
movcs r0, r2
|
||||
bcs 0f
|
||||
ldr r0, [lr, #0x18] @ 1ci
|
||||
mov r0, r0, lsr #16
|
||||
lookup_tl r0 @ r0=c2
|
||||
|
||||
0:
|
||||
add r0, r0, r2
|
||||
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r0, r0, lsr #1
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
1:
|
||||
@ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r2, #0
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2 @ r2=mem
|
||||
|
||||
2:
|
||||
str r2, [lr, #0x38] @ mem
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo4_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r0, [lr, #0x18]
|
||||
mov r0, r0, lsr #16 @ 1ci
|
||||
lookup_tl r0 @ r0=c2
|
||||
|
||||
0:
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r0, r0, lsr #1
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
1:
|
||||
@ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
2:
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo5_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r2, [lr, #0x18]
|
||||
ldr r0, [lr, #0x38] @ mem (signed)
|
||||
mov r2, r2, lsr #16
|
||||
add r0, r2, r0, lsr #1
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
0:
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
1: @ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
2:
|
||||
mov r1, r10, asr #16
|
||||
str r1, [lr, #0x38] @ mem
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo6_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r0, [lr, #0x18]
|
||||
mov r0, r0, lsr #16 @ 1ci
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
0:
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r2, r2, lsr #16 @ 1ci
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
1: @ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r5, r10, lsr #17
|
||||
add r2, r5, r2, lsr #16
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
2:
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_algo7_m
|
||||
|
||||
@ SLOT3
|
||||
make_eg_out SLOT3
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r0, #0
|
||||
bcs 0f
|
||||
ldr r0, [lr, #0x18]
|
||||
mov r0, r0, lsr #16 @ 1ci
|
||||
lookup_tl r0 @ r0=output smp
|
||||
|
||||
0:
|
||||
add r0, r0, r10, asr #16
|
||||
|
||||
@ SLOT4
|
||||
make_eg_out SLOT4
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 1f
|
||||
ldr r2, [lr, #0x1c]
|
||||
mov r2, r2, lsr #16 @ 1ci
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
1: @ SLOT2
|
||||
make_eg_out SLOT2
|
||||
cmp r1, #ENV_QUIET
|
||||
bcs 2f
|
||||
ldr r2, [lr, #0x14]
|
||||
mov r2, r2, lsr #16 @ 1ci
|
||||
lookup_tl r2
|
||||
add r0, r0, r2 @ add to smp
|
||||
|
||||
2:
|
||||
.endm
|
||||
|
||||
|
||||
.macro upd_slot1_m
|
||||
|
||||
make_eg_out SLOT1
|
||||
cmp r1, #ENV_QUIET
|
||||
movcs r10, r10, lsl #16 @ ct->op1_out <<= 16; // op1_out0 = op1_out1; op1_out1 = 0;
|
||||
bcs 0f
|
||||
ands r2, r12, #0xf000
|
||||
moveq r0, #0
|
||||
movne r2, r2, lsr #12
|
||||
addne r0, r10, r10, lsl #16
|
||||
movne r0, r0, asr #16
|
||||
movne r0, r0, lsl r2
|
||||
|
||||
ldr r2, [lr, #0x10]
|
||||
mov r0, r0, lsr #16
|
||||
add r0, r0, r2, lsr #16
|
||||
lookup_tl r0
|
||||
mov r10,r10,lsl #16 @ ct->op1_out <<= 16;
|
||||
mov r0, r0, lsl #16
|
||||
orr r10,r10, r0, lsr #16
|
||||
|
||||
0:
|
||||
.endm
|
||||
|
||||
|
||||
/*
|
||||
.global update_eg_phase @ FM_SLOT *SLOT, UINT32 eg_cnt
|
||||
|
||||
update_eg_phase:
|
||||
stmfd sp!, {r5,r6}
|
||||
mov r5, r0 @ slot
|
||||
ldrh r3, [r5,#0x18] @ tl
|
||||
ldrh r6, [r5,#0x1a] @ volume
|
||||
add r6, r6, r3
|
||||
update_eg_phase_slot SLOT1
|
||||
mov r0, r6
|
||||
ldmfd sp!, {r5,r6}
|
||||
bx lr
|
||||
.pool
|
||||
|
||||
|
||||
.global advance_lfo @ int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt
|
||||
|
||||
advance_lfo:
|
||||
mov r12, r0, lsl #16
|
||||
advance_lfo_m
|
||||
mov r0, r12, lsr #16
|
||||
bx lr
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo0 @ chan_rend_context *c
|
||||
upd_algo0:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo0_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo1 @ chan_rend_context *c
|
||||
upd_algo1:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo1_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo2 @ chan_rend_context *c
|
||||
upd_algo2:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo2_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo3 @ chan_rend_context *c
|
||||
upd_algo3:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo3_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo4 @ chan_rend_context *c
|
||||
upd_algo4:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo4_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo5 @ chan_rend_context *c
|
||||
upd_algo5:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo5_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo6 @ chan_rend_context *c
|
||||
upd_algo6:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo6_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_algo7 @ chan_rend_context *c
|
||||
upd_algo7:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_algo7_m
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
|
||||
|
||||
.global upd_slot1 @ chan_rend_context *c
|
||||
upd_slot1:
|
||||
stmfd sp!, {r4-r10,lr}
|
||||
mov lr, r0
|
||||
|
||||
ldr r3, =ym_sin_tab
|
||||
ldr r5, =ym_tl_tab
|
||||
ldmia lr, {r6-r7}
|
||||
ldr r10, [lr, #0x54]
|
||||
ldr r12, [lr, #0x4c]
|
||||
|
||||
upd_slot1_m
|
||||
str r10, [lr, #0x38]
|
||||
|
||||
ldmfd sp!, {r4-r10,pc}
|
||||
.pool
|
||||
*/
|
||||
|
||||
|
||||
@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
|
||||
@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|algo, r5=tl_tab/slot,
|
||||
@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
|
||||
.global chan_render_loop @ chan_rend_context *ct, int *buffer, int length
|
||||
|
||||
chan_render_loop:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
mov lr, r0
|
||||
mov r4, r2, lsl #8 @ no more 24 bits here
|
||||
ldr r12, [lr, #0x4c]
|
||||
ldr r0, [lr, #0x50]
|
||||
mov r11, r1
|
||||
and r0, r0, #7
|
||||
orr r4, r4, r0 @ (length<<8)|algo
|
||||
add r0, lr, #0x44
|
||||
ldmia r0, {r8,r9} @ eg_timer, eg_timer_add
|
||||
ldr r10, [lr, #0x54] @ op1_out
|
||||
ldmia lr, {r6,r7} @ load volumes
|
||||
|
||||
tst r12, #8 @ lfo?
|
||||
beq crl_loop
|
||||
|
||||
crl_loop_lfo:
|
||||
add r0, lr, #0x30
|
||||
ldmia r0, {r1,r2}
|
||||
add r2, r2, r1
|
||||
str r2, [lr, #0x30]
|
||||
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt
|
||||
advance_lfo_m
|
||||
|
||||
crl_loop:
|
||||
subs r4, r4, #0x100
|
||||
bmi crl_loop_end
|
||||
|
||||
@ -- EG --
|
||||
add r8, r8, r9
|
||||
cmp r8, #EG_TIMER_OVERFLOW
|
||||
bcc eg_done
|
||||
add r0, lr, #0x3c
|
||||
ldmia r0, {r1,r5} @ eg_cnt, CH
|
||||
eg_loop:
|
||||
sub r8, r8, #EG_TIMER_OVERFLOW
|
||||
add r1, r1, #1
|
||||
@ SLOT1 (0)
|
||||
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
|
||||
update_eg_phase_slot SLOT1
|
||||
add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT2 (2)
|
||||
update_eg_phase_slot SLOT2
|
||||
sub r5, r5, #SLOT_STRUCT_SIZE @ SLOT3 (1)
|
||||
update_eg_phase_slot SLOT3
|
||||
add r5, r5, #SLOT_STRUCT_SIZE*2 @ SLOT4 (3)
|
||||
update_eg_phase_slot SLOT4
|
||||
|
||||
cmp r8, #EG_TIMER_OVERFLOW
|
||||
subcs r5, r5, #SLOT_STRUCT_SIZE*3
|
||||
bcs eg_loop
|
||||
str r1, [lr, #0x3c]
|
||||
|
||||
eg_done:
|
||||
|
||||
@ -- disabled? --
|
||||
and r0, r12, #0xC
|
||||
cmp r0, #0xC
|
||||
beq crl_loop_lfo
|
||||
cmp r0, #0x4
|
||||
beq crl_loop
|
||||
|
||||
@ -- SLOT1 --
|
||||
ldr r3, =ym_tl_tab
|
||||
|
||||
@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
|
||||
@ r0-r2=scratch, r3=tl_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
|
||||
upd_slot1_m
|
||||
|
||||
@ -- SLOT2+ --
|
||||
and r0, r4, #7
|
||||
ldr pc, [pc, r0, lsl #2]
|
||||
nop
|
||||
.word crl_algo0
|
||||
.word crl_algo1
|
||||
.word crl_algo2
|
||||
.word crl_algo3
|
||||
.word crl_algo4
|
||||
.word crl_algo5
|
||||
.word crl_algo6
|
||||
.word crl_algo7
|
||||
.pool
|
||||
|
||||
crl_algo0:
|
||||
upd_algo0_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo1:
|
||||
upd_algo1_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo2:
|
||||
upd_algo2_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo3:
|
||||
upd_algo3_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo4:
|
||||
upd_algo4_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo5:
|
||||
upd_algo5_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo6:
|
||||
upd_algo6_m
|
||||
b crl_algo_done
|
||||
.pool
|
||||
|
||||
crl_algo7:
|
||||
upd_algo7_m
|
||||
.pool
|
||||
|
||||
|
||||
crl_algo_done:
|
||||
@ -- WRITE SAMPLE --
|
||||
tst r0, r0
|
||||
beq ctl_sample_skip
|
||||
tst r12, #1
|
||||
beq ctl_sample_mono
|
||||
|
||||
tst r12, #0x20 @ L
|
||||
ldrne r1, [r11]
|
||||
addeq r11, r11, #4
|
||||
addne r1, r0, r1
|
||||
strne r1, [r11], #4
|
||||
tst r12, #0x10 @ R
|
||||
ldrne r1, [r11]
|
||||
addeq r11, r11, #4
|
||||
addne r1, r0, r1
|
||||
strne r1, [r11], #4
|
||||
b crl_do_phase
|
||||
|
||||
ctl_sample_skip:
|
||||
and r1, r12, #1
|
||||
add r1, r1, #1
|
||||
add r11,r11, r1, lsl #2
|
||||
b crl_do_phase
|
||||
|
||||
ctl_sample_mono:
|
||||
ldr r1, [r11]
|
||||
add r1, r0, r1
|
||||
str r1, [r11], #4
|
||||
|
||||
crl_do_phase:
|
||||
@ -- PHASE UPDATE --
|
||||
add r5, lr, #0x10
|
||||
ldmia r5, {r0-r1}
|
||||
add r5, lr, #0x20
|
||||
ldmia r5, {r2-r3}
|
||||
add r5, lr, #0x10
|
||||
add r0, r0, r2
|
||||
add r1, r1, r3
|
||||
stmia r5!,{r0-r1}
|
||||
ldmia r5, {r0-r1}
|
||||
add r5, lr, #0x28
|
||||
ldmia r5, {r2-r3}
|
||||
add r5, lr, #0x18
|
||||
add r0, r0, r2
|
||||
add r1, r1, r3
|
||||
stmia r5, {r0-r1}
|
||||
|
||||
tst r12, #8
|
||||
bne crl_loop_lfo
|
||||
b crl_loop
|
||||
|
||||
|
||||
crl_loop_end:
|
||||
str r8, [lr, #0x44] @ eg_timer
|
||||
str r12, [lr, #0x4c] @ pack (for lfo_ampm)
|
||||
str r10, [lr, #0x54] @ op1_out
|
||||
ldmfd sp!, {r4-r11,pc}
|
||||
|
||||
.pool
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue