return inflateEnd(&stream);\r
}\r
\r
+static const char *get_ext(const char *path)\r
+{\r
+ const char *ext;\r
+ if (strlen(path) < 4)\r
+ return ""; // no ext\r
+\r
+ // allow 2 or 3 char extensions for now\r
+ ext = path + strlen(path) - 2;\r
+ if (ext[-1] != '.') ext--;\r
+ if (ext[-1] != '.')\r
+ return "";\r
+ return ext;\r
+}\r
+\r
pm_file *pm_open(const char *path)\r
{\r
pm_file *file = NULL;\r
const char *ext;\r
FILE *f;\r
\r
- if (path == NULL) return NULL;\r
-\r
- if (strlen(path) < 5) ext = NULL; // no ext\r
- else ext = path + strlen(path) - 3;\r
+ if (path == NULL)\r
+ return NULL;\r
\r
- if (ext && strcasecmp(ext, "zip") == 0)\r
+ ext = get_ext(path);\r
+ if (strcasecmp(ext, "zip") == 0)\r
{\r
struct zipent *zipentry;\r
gzFile gzf = NULL;\r
int i;\r
\r
zipfile = openzip(path);\r
-\r
if (zipfile != NULL)\r
{\r
/* search for suitable file (right extension or large enough file) */\r
while ((zipentry = readzip(zipfile)) != NULL)\r
{\r
- if (zipentry->uncompressed_size >= 128*1024) goto found_rom_zip;\r
- if (strlen(zipentry->name) < 5) continue;\r
+ ext = get_ext(zipentry->name);\r
\r
- ext = zipentry->name + strlen(zipentry->name) - 2;\r
- if (ext[-1] != '.') ext--;\r
- if (ext[-1] != '.') ext--;\r
+ if (zipentry->uncompressed_size >= 32*1024)\r
+ goto found_rom_zip;\r
\r
for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++)\r
- if (strcasecmp(ext, rom_exts[i]) == 0) goto found_rom_zip;\r
+ if (strcasecmp(ext, rom_exts[i]) == 0)\r
+ goto found_rom_zip;\r
}\r
\r
/* zipfile given, but nothing found suitable for us inside */\r
gzf = zip2gz(zipfile, zipentry);\r
if (gzf == NULL) goto zip_failed;\r
\r
- file = malloc(sizeof(*file));\r
+ file = calloc(1, sizeof(*file));\r
if (file == NULL) goto zip_failed;\r
file->file = zipfile;\r
file->param = gzf;\r
file->size = zipentry->uncompressed_size;\r
file->type = PMT_ZIP;\r
+ strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
return file;\r
\r
zip_failed:\r
return NULL;\r
}\r
}\r
- else if (ext && strcasecmp(ext, "cso") == 0)\r
+ else if (strcasecmp(ext, "cso") == 0)\r
{\r
cso_struct *cso = NULL, *tmp = NULL;\r
int size;\r
cso->fpos_in = ftell(f);\r
cso->fpos_out = 0;\r
cso->block_in_buff = -1;\r
- file = malloc(sizeof(*file));\r
+ file = calloc(1, sizeof(*file));\r
if (file == NULL) goto cso_failed;\r
file->file = f;\r
file->param = cso;\r
f = fopen(path, "rb");\r
if (f == NULL) return NULL;\r
\r
- file = malloc(sizeof(*file));\r
+ file = calloc(1, sizeof(*file));\r
if (file == NULL) {\r
fclose(f);\r
return NULL;\r
file->param = NULL;\r
file->size = ftell(f);\r
file->type = PMT_UNCOMPRESSED;\r
+ strncpy(file->ext, ext, sizeof(file->ext) - 1);\r
fseek(f, 0, SEEK_SET);\r
\r
#ifndef __EPOC32__ // makes things worse on Symbian\r
return rom;\r
}\r
\r
-static unsigned char *PicoCartAlloc(int filesize)\r
+static unsigned char *PicoCartAlloc(int filesize, int is_sms)\r
{\r
int alloc_size;\r
unsigned char *rom;\r
\r
- if (PicoAHW & PAHW_MCD) return cd_realloc(NULL, filesize);\r
+ if (PicoAHW & PAHW_MCD)\r
+ return cd_realloc(NULL, filesize);\r
+\r
+ if (is_sms) {\r
+ // make size power of 2 for easier banking handling\r
+ int s = 0, tmp = filesize;\r
+ while ((tmp >>= 1) != 0)\r
+ s++;\r
+ if (filesize > (1 << s))\r
+ s++;\r
+ alloc_size = 1 << s;\r
+ }\r
+ else {\r
+ // align to 512K for memhandlers\r
+ alloc_size = (filesize + 0x7ffff) & ~0x7ffff;\r
+ }\r
\r
- alloc_size=filesize+0x7ffff;\r
- if((filesize&0x3fff)==0x200) alloc_size-=0x200;\r
- alloc_size&=~0x7ffff; // use alloc size of multiples of 512K, so that memhandlers could be set up more efficiently\r
- if((filesize&0x3fff)==0x200) alloc_size+=0x200;\r
- else if(alloc_size-filesize < 4) alloc_size+=4; // padding for out-of-bound exec protection\r
+ if (alloc_size - filesize < 4)\r
+ alloc_size += 4; // padding for out-of-bound exec protection\r
\r
// Allocate space for the rom plus padding\r
- rom=(unsigned char *)malloc(alloc_size);\r
- if(rom) memset(rom+alloc_size-0x80000,0,0x80000);\r
+ rom = calloc(alloc_size, 1);\r
return rom;\r
}\r
\r
int PicoCartLoad(pm_file *f,unsigned char **prom,unsigned int *psize,int is_sms)\r
{\r
- unsigned char *rom=NULL; int size, bytes_read;\r
- if (f==NULL) return 1;\r
+ unsigned char *rom;\r
+ int size, bytes_read;\r
+\r
+ if (f == NULL)\r
+ return 1;\r
\r
- size=f->size;\r
+ size = f->size;\r
if (size <= 0) return 1;\r
- size=(size+3)&~3; // Round up to a multiple of 4\r
+ size = (size+3)&~3; // Round up to a multiple of 4\r
\r
// Allocate space for the rom plus padding\r
- rom=PicoCartAlloc(size);\r
- if (rom==NULL) {\r
+ rom = PicoCartAlloc(size, is_sms);\r
+ if (rom == NULL) {\r
elprintf(EL_STATUS, "out of memory (wanted %i)", size);\r
return 2;\r
}\r
}\r
\r
// Check for SMD:\r
- if (size >= 0x4200 && (size&0x3fff)==0x200 &&\r
+ if (size >= 0x4200 && (size&0x3fff) == 0x200 &&\r
((rom[0x2280] == 'S' && rom[0x280] == 'E') || (rom[0x280] == 'S' && rom[0x2281] == 'E'))) {\r
+ elprintf(EL_STATUS, "SMD format detected.");\r
DecodeSmd(rom,size); size-=0x200; // Decode and byteswap SMD\r
}\r
else Byteswap(rom,size); // Just byteswap\r
}\r
+ else\r
+ {\r
+ if (size >= 0x4200 && (size&0x3fff) == 0x200) {\r
+ elprintf(EL_STATUS, "SMD format detected.");\r
+ // at least here it's not interleaved\r
+ size -= 0x200;\r
+ memmove(rom, rom + 0x200, size);\r
+ }\r
+ }\r
\r
- if (prom) *prom=rom;\r
- if (psize) *psize=size;\r
+ if (prom) *prom = rom;\r
+ if (psize) *psize = size;\r
\r
return 0;\r
}\r
void PDebugDumpMem(void)
{
- dump_ram(Pico.ram, "dumps/ram.bin");
dump_ram_noswab(Pico.zram, "dumps/zram.bin");
- dump_ram(Pico.vram, "dumps/vram.bin");
dump_ram(Pico.cram, "dumps/cram.bin");
- dump_ram(Pico.vsram,"dumps/vsram.bin");
+
+ if (PicoAHW & PAHW_SMS)
+ {
+ dump_ram_noswab(Pico.vramb, "dumps/vram.bin");
+ }
+ else
+ {
+ dump_ram(Pico.ram, "dumps/ram.bin");
+ dump_ram(Pico.vram, "dumps/vram.bin");
+ dump_ram(Pico.vsram,"dumps/vsram.bin");
+ }
if (PicoAHW & PAHW_MCD)
{
{
int lines, line_sample;
+ if (PicoAHW & PAHW_SMS)
+ return;
+
if (Pico.m.pal) {
lines = 312;
line_sample = 68;
timers_cycle();
}
+void PDebugCPUStep(void)
+{
+ if (PicoAHW & PAHW_SMS)
+ z80_run(1);
+ else
+ SekStepM68k();
+}
+
void PDebugShowSprite(unsigned short *screen, int stride, int which);
void PDebugDumpMem(void);
void PDebugZ80Frame(void);
+void PDebugCPUStep(void);
#else\r
unsigned char HighCol[8+320+8];\r
#endif\r
-unsigned short DefOutBuff[320*2];\r
+static unsigned int DefOutBuff[320*2/2];\r
void *DrawLineDest=DefOutBuff; // pointer to dest buffer where to draw this line to\r
\r
static int HighCacheA[41+1]; // caches for high layers\r
int len, rs = rendstatus;\r
static int dirty_count;\r
\r
- if (!sh && Pico.m.dirtyPal == 1 && DrawScanline < 222)\r
+ if (!sh && Pico.m.dirtyPal == 1)\r
{\r
// a hack for mid-frame palette changes\r
if (!(rs & PDRAW_SONIC_MODE))\r
\r
// --------------------------------------------\r
\r
-static void DrawBlankedLine(void)\r
-{\r
- int sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight?\r
-\r
- if (PicoScanBegin != NULL)\r
- PicoScanBegin(DrawScanline);\r
-\r
- BackFill(Pico.video.reg[7], sh);\r
-\r
- if (FinalizeLine != NULL)\r
- FinalizeLine(sh);\r
-\r
- if (PicoScanEnd != NULL)\r
- PicoScanEnd(DrawScanline);\r
-}\r
-\r
static int DrawDisplay(int sh)\r
{\r
unsigned char *sprited = &HighLnSpr[DrawScanline][0];\r
rendstatus = 0;\r
if ((Pico.video.reg[12]&6) == 6)\r
rendstatus |= PDRAW_INTERLACE; // interlace mode\r
+ if (Pico.video.reg[1] & 8)\r
+ rendstatus |= PDRAW_240LINES;\r
\r
- if (Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed\r
+ if (Pico.m.dirtyPal)\r
+ Pico.m.dirtyPal = 2; // reset dirty if needed\r
\r
DrawScanline=0;\r
PrepareSprites(1);\r
skip_next_line=0;\r
}\r
\r
-static void PicoLine(void)\r
+static void DrawBlankedLine(int line, int offs)\r
+{\r
+ int sh = (Pico.video.reg[0xC]&8)>>3; // shadow/hilight?\r
+\r
+ if (PicoScanBegin != NULL)\r
+ PicoScanBegin(line + offs);\r
+\r
+ BackFill(Pico.video.reg[7], sh);\r
+\r
+ if (FinalizeLine != NULL)\r
+ FinalizeLine(sh);\r
+\r
+ if (PicoScanEnd != NULL)\r
+ PicoScanEnd(line + offs);\r
+}\r
+\r
+static void PicoLine(int line, int offs)\r
{\r
int sh;\r
- if (skip_next_line>0) { skip_next_line--; return; } // skip rendering lines\r
+ if (skip_next_line > 0) {\r
+ skip_next_line--;\r
+ return;\r
+ }\r
\r
sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight?\r
\r
+ DrawScanline = line;\r
if (PicoScanBegin != NULL)\r
- skip_next_line = PicoScanBegin(DrawScanline);\r
+ skip_next_line = PicoScanBegin(line + offs);\r
\r
// Draw screen:\r
BackFill(Pico.video.reg[7], sh);\r
FinalizeLine(sh);\r
\r
if (PicoScanEnd != NULL)\r
- skip_next_line = PicoScanEnd(DrawScanline);\r
+ skip_next_line = PicoScanEnd(line + offs);\r
}\r
\r
void PicoDrawSync(int to, int blank_last_line)\r
{\r
- for (; DrawScanline < to; DrawScanline++)\r
+ int line, offs = 0;\r
+\r
+ if (!(rendstatus & PDRAW_240LINES))\r
+ offs = 8;\r
+\r
+ for (line = DrawScanline; line < to; line++)\r
{\r
#if !CAN_HANDLE_240_LINES\r
- if (DrawScanline >= 224) break;\r
+ if (line >= 224) break;\r
#endif\r
- PicoLine();\r
+ PicoLine(line, offs);\r
}\r
\r
#if !CAN_HANDLE_240_LINES\r
- if (DrawScanline >= 224) { DrawScanline = 240; return; }\r
+ if (line >= 224) {\r
+ DrawScanline = 240;\r
+ return;\r
+ }\r
#endif\r
\r
// last line\r
- if (DrawScanline <= to)\r
+ if (line <= to)\r
{\r
if (blank_last_line)\r
- DrawBlankedLine();\r
- else PicoLine();\r
- DrawScanline++;\r
+ DrawBlankedLine(line, offs);\r
+ else PicoLine(line, offs);\r
+ line++;\r
}\r
+ DrawScanline = line;\r
}\r
\r
void PicoDrawSetColorFormat(int which)\r
case 0: FinalizeLine = FinalizeLineBGR444; break;\r
default:FinalizeLine = NULL; break;\r
}\r
+ PicoDrawSetColorFormatMode4(which);\r
#if OVERRIDE_HIGHCOL\r
- if (which) HighCol=DefHighCol;\r
+ if (which)\r
+ HighCol=DefHighCol;\r
#endif\r
}\r
\r
+/*
+ * TODO:
+ * - TMS9918 modes?
+ * - gg mode?
+ * - column scroll (reg 0 bit7)
+ * - 224/240 line modes
+ * - doubled sprites
+ */
#include "pico_int.h"
static void (*FinalizeLineM4)(void);
static int skip_next_line;
+static int screen_offset;
#define PLANAR_PIXEL(x,p) \
t = pack & (0x80808080 >> p); \
return 1; /* Tile blank */
}
-struct TileStrip
+static void draw_sprites(int scanline)
{
- int nametab; // Position in VRAM of name table (for this tile line)
- int line; // Line number in pixels 0x000-0x3ff within the virtual tilemap
- int hscroll; // Horizontal scroll value in pixels for the line
- int xmask; // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap
- int *hc; // cache for high tile codes and their positions
- int cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320)
-};
-
-static void DrawStrip(struct TileStrip *ts, int cellskip)
+ struct PicoVideo *pv = &Pico.video;
+ unsigned int sprites_addr[8];
+ unsigned int sprites_x[8];
+ unsigned char *sat;
+ int xoff = 8; // relative to HighCol, which is (screen - 8)
+ int sprite_base, addr_mask;
+ int i, s, h;
+
+ if (pv->reg[0] & 8)
+ xoff = 0;
+
+ sat = (unsigned char *)Pico.vram + ((pv->reg[5] & 0x7e) << 7);
+ if (pv->reg[1] & 2) {
+ addr_mask = 0xfe; h = 16;
+ } else {
+ addr_mask = 0xff; h = 8;
+ }
+ sprite_base = (pv->reg[6] & 4) << (13-2-1);
+
+ for (i = s = 0; i < 64 && s < 8; i++)
+ {
+ int y;
+ y = sat[i] + 1;
+ if (y == 0xd1)
+ break;
+ if (y + h <= scanline || scanline < y)
+ continue; // not on this line
+
+ sprites_x[s] = xoff + sat[0x80 + i*2];
+ sprites_addr[s] = sprite_base + ((sat[0x80 + i*2 + 1] & addr_mask) << (5-1)) +
+ ((scanline - y) << (2-1));
+ s++;
+ }
+
+ // now draw all sprites backwards
+ for (--s; s >= 0; s--)
+ TileNormM4(sprites_x[s], sprites_addr[s], 0x10);
+}
+
+// tilex_ty_prio merged to reduce register pressure
+static void draw_strip(const unsigned short *nametab, int dx, int cells, int tilex_ty_prio)
{
- int tilex,dx,ty,code=0,addr=0,cells;
- int oldcode=-1,blank=-1; // The tile we know is blank
- int pal=0;
+ int oldcode = -1, blank = -1; // The tile we know is blank
+ int addr = 0, pal = 0;
// Draw tiles across screen:
- tilex=((-ts->hscroll)>>3)+cellskip;
- ty=(ts->line&7)<<1; // Y-Offset into tile
- dx=((ts->hscroll-1)&7)+1;
- cells = ts->cells - cellskip;
- if (dx != 8) cells++; // have hscroll, need to draw 1 cell more
- dx+=cellskip<<3;
-
- for (; cells > 0; dx+=8,tilex++,cells--)
+ for (; cells > 0; dx += 8, tilex_ty_prio++, cells--)
{
- int zero;
+ int code, zero;
- code=Pico.vram[ts->nametab + (tilex & 0x1f)];
- if (code==blank) continue;
+ code = nametab[tilex_ty_prio & 0x1f];
+ if (code == blank)
+ continue;
+ if ((code ^ tilex_ty_prio) & 0x1000) // priority differs?
+ continue;
- if (code!=oldcode) {
+ if (code != oldcode) {
oldcode = code;
// Get tile address/2:
- addr=(code&0x1ff)<<4;
- addr+=ty;
- if (code&0x0400) addr^=0xe; // Y-flip
+ addr = (code & 0x1ff) << 4;
+ addr += tilex_ty_prio >> 16;
+ if (code & 0x0400)
+ addr ^= 0xe; // Y-flip
- pal=((code>>7)&0x10);
+ pal = (code>>7) & 0x10;
}
- if (code&0x0200) zero=TileFlipM4(dx,addr,pal);
- else zero=TileNormM4(dx,addr,pal);
+ if (code&0x0200) zero = TileFlipM4(dx, addr, pal);
+ else zero = TileNormM4(dx, addr, pal);
- if (zero) blank=code; // We know this tile is blank now
+ if (zero)
+ blank = code; // We know this tile is blank now
}
}
-static void DrawLayer(int cellskip, int maxcells)
+static void DrawDisplayM4(int scanline)
{
- struct PicoVideo *pvid=&Pico.video;
- struct TileStrip ts;
- int vscroll;
-
- ts.cells=maxcells;
-
- // Find name table:
- ts.nametab=(pvid->reg[2]&0x0e) << (10-1);
-
- // Get horizontal scroll value, will be masked later
- ts.hscroll=0;//pvid->reg[8];
- vscroll=0;//pvid->reg[9]; // Get vertical scroll value
+ struct PicoVideo *pv = &Pico.video;
+ unsigned short *nametab;
+ int line, tilex, dx, ty, cells;
+ int cellskip = 0; // XXX
+ int maxcells = 32;
// Find the line in the name table
- ts.line=(vscroll+DrawScanline)&0xff;
- ts.nametab+=(ts.line>>3) << (6-1);
+ line = pv->reg[9] + scanline; // vscroll + scanline
+ if (line >= 224)
+ line -= 224;
- DrawStrip(&ts, cellskip);
-}
-
-static void DrawDisplayM4(void)
-{
- DrawLayer(0, 32);
+ // Find name table:
+ nametab = Pico.vram;
+ nametab += (pv->reg[2] & 0x0e) << (10-1);
+ nametab += (line>>3) << (6-1);
+
+ dx = pv->reg[8]; // hscroll
+ if (scanline < 16 && (pv->reg[0] & 0x40))
+ dx = 0; // hscroll disabled for top 2 rows
+
+ tilex = ((-dx >> 3) + cellskip) & 0x1f;
+ ty = (line & 7) << 1; // Y-Offset into tile
+ cells = maxcells - cellskip;
+
+ dx = ((dx - 1) & 7) + 1;
+ if (dx != 8)
+ cells++; // have hscroll, need to draw 1 cell more
+ dx += cellskip << 3;
+
+ // low priority tiles
+ if (PicoDrawMask & PDRAW_LAYERB_ON)
+ draw_strip(nametab, dx, cells, tilex | 0x0000 | (ty << 16));
+
+ // sprites
+ if (PicoDrawMask & PDRAW_SPRITES_LOW_ON)
+ draw_sprites(scanline);
+
+ // high priority tiles (use virtual layer switch just for fun)
+ if (PicoDrawMask & PDRAW_LAYERA_ON)
+ draw_strip(nametab, dx, cells, tilex | 0x1000 | (ty << 16));
+
+ if (pv->reg[0] & 0x20)
+ // first column masked
+ ((int *)HighCol)[2] = ((int *)HighCol)[3] = 0xe0e0e0e0;
}
void PicoFrameStartMode4(void)
{
- DrawScanline = 0;
skip_next_line = 0;
+ screen_offset = 24;
+ rendstatus = PDRAW_192LINES;
+ if ((Pico.video.reg[0] & 6) == 6 && (Pico.video.reg[1] & 0x18)) {
+ rendstatus &= ~PDRAW_192LINES;
+ if (Pico.video.reg[1] & 0x08) {
+ screen_offset = 0;
+ rendstatus |= PDRAW_240LINES;
+ }
+ else // it's 224 lines
+ screen_offset = 8;
+ }
}
void PicoLineMode4(int line)
return;
}
- DrawScanline = line;
-
if (PicoScanBegin != NULL)
- skip_next_line = PicoScanBegin(DrawScanline);
+ skip_next_line = PicoScanBegin(line + screen_offset);
// Draw screen:
- BackFill((Pico.video.reg[7] & 0x0f) | 0x10, 0);
+ BackFill(Pico.video.reg[7] & 0x0f, 0);
if (Pico.video.reg[1] & 0x40)
- DrawDisplayM4();
+ DrawDisplayM4(line);
if (FinalizeLineM4 != NULL)
FinalizeLineM4();
if (PicoScanEnd != NULL)
- skip_next_line = PicoScanEnd(DrawScanline);
+ skip_next_line = PicoScanEnd(line + screen_offset);
}
void PicoDoHighPal555M4(void)
}
}
+static void FinalizeLine8bitM4(void)
+{
+ memcpy32(DrawLineDest, (int *)(HighCol+8), 256/4);
+}
+
void PicoDrawSetColorFormatMode4(int which)
{
switch (which)
{
+ case 2: FinalizeLineM4 = FinalizeLine8bitM4; break;
case 1: FinalizeLineM4 = FinalizeLineRGB555M4; break;
default:FinalizeLineM4 = NULL; break;
}
-#if OVERRIDE_HIGHCOL
- if (which)
- HighCol = DefHighCol;
-#endif
}
\r
void PicoFrameDrawOnly(void)\r
{\r
- PicoFrameStart();\r
- PicoDrawSync(223, 0);\r
+ if (!(PicoAHW & PAHW_SMS)) {\r
+ PicoFrameStart();\r
+ PicoDrawSync(223, 0);\r
+ } else {\r
+ PicoFrameDrawOnlyMS();\r
+ }\r
}\r
\r
void PicoGetInternal(pint_t which, pint_ret_t *r)\r
void *param; /* additional file related field */\r
unsigned int size; /* size */\r
pm_type type;\r
+ char ext[4];\r
} pm_file;\r
pm_file *pm_open(const char *path);\r
size_t pm_read(void *ptr, size_t bytes, pm_file *stream);\r
#define PDRAW_SONIC_MODE (1<<5) // mid-frame palette changes for 8bit renderer\r
#define PDRAW_PLANE_HI_PRIO (1<<6) // have layer with all hi prio tiles (mk3)\r
#define PDRAW_SHHI_DONE (1<<7) // layer sh/hi already processed\r
+#define PDRAW_240LINES (1<<8) // 240 line display (224 if not set)\r
+#define PDRAW_192LINES (1<<9) // 192 line display (for SMS games)\r
extern int rendstatus;\r
extern unsigned short HighPal[0x100];\r
\r
extern unsigned short *PicoCramHigh; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)\r
extern void (*PicoPrepareCram)(); // prepares PicoCramHigh for renderer to use\r
\r
-// mode4.c\r
-void PicoDrawSetColorFormatMode4(int which);\r
-\r
// sound.c\r
extern int PsndRate,PsndLen;\r
extern short *PsndOut;\r
void PicoFrameStartMode4(void);\r
void PicoLineMode4(int line);\r
void PicoDoHighPal555M4(void);\r
+void PicoDrawSetColorFormatMode4(int which);\r
\r
// memory.c\r
PICO_INTERNAL void PicoInitPc(unsigned int pc);\r
void PicoResetMS(void);\r
void PicoMemSetupMS(void);\r
void PicoFrameMS(void);\r
+void PicoFrameDrawOnlyMS(void);\r
\r
// emulation event logging\r
#ifndef EL_LOGMASK\r
+/*
+ * TODO:
+ * - start in a state as if BIOS ran
+ * - remaining status flags (OVR/COL)
+ * - RAM support in mapper
+ * - region support
+ * - Pause button (NMI)
+ * - SN76496 DAC-like usage
+ * - H counter
+ */
#include "pico_int.h"
#include "sound/sn76496.h"
case 0x40: /* V counter */
d = Pico.video.v_counter;
+ elprintf(EL_HVCNT, "V counter read: %02x", d);
break;
case 0x41: /* H counter */
d = Pico.m.rotate++;
+ elprintf(EL_HVCNT, "H counter read: %02x", d);
break;
case 0x80:
}
}
+static int bank_mask;
+
static void write_bank(unsigned short a, unsigned char d)
{
- d &= 0x3f; // XXX
switch (a & 0x0f)
{
case 0x0c:
+ elprintf(EL_STATUS|EL_ANOMALY, "%02x written to control reg!", d);
break;
case 0x0d:
if (d != 0)
elprintf(EL_STATUS|EL_ANOMALY, "bank0 changed to %d!", d);
break;
case 0x0e:
+ d &= bank_mask;
z80_map_set(z80_read_map, 0x4000, 0x7fff, Pico.rom + (d << 14), 0);
#ifdef _USE_CZ80
Cz80_Set_Fetch(&CZ80, 0x4000, 0x7fff, (UINT32)Pico.rom + (d << 14));
#endif
break;
case 0x0f:
+ d &= bank_mask;
z80_map_set(z80_read_map, 0x8000, 0xbfff, Pico.rom + (d << 14), 0);
#ifdef _USE_CZ80
Cz80_Set_Fetch(&CZ80, 0x8000, 0xbfff, (UINT32)Pico.rom + (d << 14));
void PicoPowerMS(void)
{
+ int s, tmp;
+
memset(&Pico.ram,0,(unsigned int)&Pico.rom-(unsigned int)&Pico.ram);
memset(&Pico.video,0,sizeof(Pico.video));
memset(&Pico.m,0,sizeof(Pico.m));
Pico.m.pal = 0;
+ // calculate a mask for bank writes.
+ // ROM loader has aligned the size for us, so this is safe.
+ s = 0; tmp = Pico.romsize;
+ while ((tmp >>= 1) != 0)
+ s++;
+ if (Pico.romsize > (1 << s))
+ s++;
+ tmp = 1 << s;
+ bank_mask = (tmp - 1) >> 14;
+
PicoReset();
}
int cycles_line = is_pal ? 58020 : 58293; /* (226.6 : 227.7) * 256 */
int cycles_done = 0, cycles_aim = 0;
int lines_vis = 192;
+ int hint; // Hint counter
int y;
PicoFrameStartMode4();
+ hint = pv->reg[0x0a];
for (y = 0; y < lines; y++)
{
if (y < lines_vis)
PicoLineMode4(y);
+
+ if (y <= lines_vis)
+ {
+ if (--hint < 0)
+ {
+ hint = pv->reg[0x0a];
+ pv->pending_ints |= 2;
+ if (pv->reg[0] & 0x10) {
+ elprintf(EL_INTS, "hint");
+ z80_int();
+ }
+ }
+ }
else if (y == lines_vis + 1) {
- Pico.video.pending_ints |= 1;
- if (Pico.video.reg[1] & 0x20) {
+ pv->pending_ints |= 1;
+ if (pv->reg[1] & 0x20) {
elprintf(EL_INTS, "vint");
z80_int();
}
PsndGetSamplesMS();
}
+void PicoFrameDrawOnlyMS(void)
+{
+ int lines_vis = 192;
+ int y;
+
+ PicoFrameStartMode4();
+
+ for (y = 0; y < lines_vis; y++)
+ PicoLineMode4(y);
+}
+
static int detect_media(const char *fname)\r
{\r
static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 };\r
+ static const char *sms_exts[] = { "sms", "gg", "sg" };\r
+ static const char *md_exts[] = { "gen", "bin", "smd" };\r
+ char buff0[32], buff[32];\r
+ unsigned short *d16;\r
pm_file *pmf;\r
- char buff[32];\r
char ext[5];\r
int i;\r
\r
if (pmf == NULL)\r
return PM_BAD;\r
\r
- if (pm_read(buff, 32, pmf) != 32) {\r
+ if (pm_read(buff0, 32, pmf) != 32) {\r
pm_close(pmf);\r
return PM_BAD;\r
}\r
\r
- if (strncasecmp("SEGADISCSYSTEM", buff + 0x00, 14) == 0 ||\r
- strncasecmp("SEGADISCSYSTEM", buff + 0x10, 14) == 0) {\r
+ if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 ||\r
+ strncasecmp("SEGADISCSYSTEM", buff0 + 0x10, 14) == 0) {\r
pm_close(pmf);\r
return PM_CD;\r
}\r
\r
+ /* check for SMD evil */\r
+ if (pmf->size >= 0x4200 && (pmf->size & 0x3fff) == 0x200) {\r
+ if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200 &&\r
+ pm_read(buff, 16, pmf) == 16 &&\r
+ strncmp("TMR SEGA", buff, 8) == 0)\r
+ goto looks_like_sms;\r
+\r
+ /* could parse further but don't bother */\r
+ goto extension_check;\r
+ }\r
+\r
+ /* MD header? Act as TMSS BIOS here */\r
+ if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100 && pm_read(buff, 16, pmf) == 16) {\r
+ if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0)\r
+ goto looks_like_md;\r
+ }\r
+\r
for (i = 0; i < array_size(sms_offsets); i++) {\r
if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i])\r
- goto not_mark3; /* actually it could be but can't be detected */\r
+ continue;\r
\r
if (pm_read(buff, 16, pmf) != 16)\r
- goto not_mark3;\r
+ continue;\r
\r
- if (strncasecmp("TMR SEGA", buff, 8) == 0) {\r
- pm_close(pmf);\r
- return PM_MARK3;\r
- }\r
+ if (strncmp("TMR SEGA", buff, 8) == 0)\r
+ goto looks_like_sms;\r
+ }\r
+\r
+extension_check:\r
+ /* probably some headerless thing. Maybe check the extension after all. */\r
+ for (i = 0; i < array_size(md_exts); i++)\r
+ if (strcasecmp(pmf->ext, md_exts[i]) == 0)\r
+ goto looks_like_md;\r
+\r
+ for (i = 0; i < array_size(sms_exts); i++)\r
+ if (strcasecmp(pmf->ext, sms_exts[i]) == 0)\r
+ goto looks_like_sms;\r
+\r
+ /* If everything else fails, make a guess on the reset vector */\r
+ d16 = (unsigned short *)(buff0 + 4);\r
+ if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= pmf->size) {\r
+ lprintf("bad MD reset vector, assuming SMS\n");\r
+ goto looks_like_sms;\r
}\r
\r
-not_mark3:\r
+looks_like_md:\r
pm_close(pmf);\r
- /* the main emu function is to emulate MD, so assume MD */\r
return PM_MD_CART;\r
+\r
+looks_like_sms:\r
+ pm_close(pmf);\r
+ return PM_MARK3;\r
}\r
\r
static int extract_text(char *dest, const unsigned char *src, int len, int swab)\r
\r
shutdown_MCD();\r
PicoPatchUnload();\r
+ PicoAHW = 0;\r
\r
if (media_type == PM_CD)\r
{\r
{\r
case 0:\r
if (inp & PBTN_MOK)\r
- SekStepM68k();\r
+ PDebugCPUStep();\r
if (inp & PBTN_MA3) {\r
while (inp & PBTN_MA3)\r
inp = in_menu_wait_any(-1);\r
--- /dev/null
+platform/common/menu.o : revision.h
+
+revision.h: FORCE
+ @echo "#define REVISION \"`svn info -r HEAD | grep Revision | cut -c 11-`\"" > /tmp/r.tmp
+ @diff -q $@ /tmp/r.tmp > /dev/null 2>&1 || mv -f /tmp/r.tmp $@
+
+FORCE:
+
static int EmuScanBegin16(unsigned int num)
{
- if (!(Pico.video.reg[1]&8)) num += 8;
DrawLineDest = (unsigned short *) giz_screen + 321 * num;
if ((currentConfig.EmuOpt&0x4000) && (num&1) == 0) // (Pico.m.frame_count&1))
static int EmuScanBegin8(unsigned int num)
{
// draw like the fast renderer
- if (!(Pico.video.reg[1]&8)) num += 8;
HighCol = gfx_buffer + 328 * num;
return 0;
OBJS += ../../picoAll.o\r
else\r
OBJS += pico/area.o pico/cart.o pico/memory.o pico/misc.o pico/pico.o pico/sek.o pico/z80if.o \\r
- pico/videoport.o pico/draw2.o pico/draw.o pico/patch.o pico/debug.o\r
+ pico/videoport.o pico/draw2.o pico/draw.o pico/mode4.o pico/sms.o pico/patch.o pico/debug.o\r
# Pico - CD\r
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \\r
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \\r
all: mkdirs PicoDrive\r
\r
include ../common/common_arm.mak\r
-\r
-platform/common/menu.o : revision.h\r
-\r
-revision.h:\r
- @echo "#define REVISION \"`svn info | grep Revision | cut -c 11-`\"" > /tmp/r.tmp\r
- @diff -q $@ /tmp/r.tmp > /dev/null 2>&1 || mv -f /tmp/r.tmp $@\r
+include ../common/revision.mak\r
\r
# partial linking helps profiled builds due to section merging\r
PicoDrive.o : $(OBJS) ../common/helix/$(CROSS)helix-mp3.a\r
\r
static int EmuScanBegin16(unsigned int num)\r
{\r
- if (!(Pico.video.reg[1]&8)) num += 8;\r
DrawLineDest = (unsigned short *) g_screen_ptr + g_screen_width * num;\r
\r
return 0;\r
\r
static int EmuScanBegin8(unsigned int num)\r
{\r
- if (!(Pico.video.reg[1]&8)) num += 8;\r
DrawLineDest = (unsigned char *) g_screen_ptr + g_screen_width * num;\r
\r
return 0;\r
{\r
if ((num & 3) != 3)\r
return 0;\r
- if (!(Pico.video.reg[1] & 8))\r
- num += 8;\r
rotated_blit16(g_screen_ptr, rot_buff, num + 1,\r
!(Pico.video.reg[12] & 1) && !(PicoOpt & POPT_EN_SOFTSCALE));\r
return 0;\r
{\r
if ((num & 3) != 3)\r
return 0;\r
- if (!(Pico.video.reg[1] & 8))\r
- num += 8;\r
rotated_blit8(g_screen_ptr, rot_buff, num + 1,\r
!(Pico.video.reg[12] & 1));\r
return 0;\r
}\r
else if (currentConfig.EmuOpt & EOPT_16BPP) {\r
PicoDrawSetColorFormat(1);\r
- PicoDrawSetColorFormatMode4(1);\r
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {\r
gp2x_video_changemode(-16);\r
PicoScanBegin = EmuScanBegin16_rot;\r
$(CC) $(CFLAGS) $^ $(LDFLAGS) -lm -lpng -Wl,-Map=PicoDrive.map -o $@
mkdirs:
- mkdir -p $(DIRS)
+ @mkdir -p $(DIRS)
+
+include ../common/revision.mak
pico/carthw/svp/compiler.o : ../../pico/carthw/svp/gen_arm.c
pico/pico.o pico/cd/pico.o : ../../pico/pico_cmn.c ../../pico/pico_int.h
pico/memory.o pico/cd/memory.o : ../../pico/memory_cmn.c ../../pico/pico_int.h
-platform/common/menu.o : revision.h
-
-revision.h:
- @echo "#define REVISION \"`svn info | grep Revision | cut -c 11-`\"" > /tmp/r.tmp
- @diff -q $@ /tmp/r.tmp > /dev/null 2>&1 || mv -f /tmp/r.tmp $@
../../cpu/musashi/m68kops.c :
@make -C ../../cpu/musashi
\r
static int EmuScanBegin16(unsigned int num)\r
{\r
- if (!(Pico.video.reg[1]&8)) num += 8;\r
DrawLineDest = (unsigned short *)g_screen_ptr + num*800 + 800/2 - 320/2;\r
//int w = (Pico.video.reg[12]&1) ? 320 : 256;\r
//DrawLineDest = (unsigned short *)g_screen_ptr + num*w;\r
int sh = Pico.video.reg[0xC]&8;\r
int len, mask = 0xff;\r
\r
- if (!(Pico.video.reg[1]&8)) num += 8;\r
pd=(unsigned short *)g_screen_ptr + num*800*2 + 800/2 - 320*2/2;\r
\r
if (Pico.m.dirtyPal)\r
static int EmuScanSlowBegin(unsigned int num)
{
- if (!(Pico.video.reg[1]&8)) num += 8;
-
if (!dynamic_palette)
HighCol = (unsigned char *)VRAM_CACHED_STUFF + num * 512 + 8;
static int EmuScanSlowEnd(unsigned int num)
{
- if (!(Pico.video.reg[1]&8)) num += 8;
-
if (Pico.m.dirtyPal) {
if (!dynamic_palette) {
do_slowmode_lines(num);
\r
static int EmuScanBegin8(unsigned int num)\r
{\r
- DrawLineDest = PicoDraw2FB + 328*num + 328*8 + 8;\r
+ DrawLineDest = PicoDraw2FB + 328*num + 8;\r
\r
return 0;\r
}\r
static int u = 0, num2 = 0;\r
if(!num) u = num2 = 0;\r
\r
- DrawLineDest = PicoDraw2FB + 328*(++num2) + 328*8 + 8;\r
+ DrawLineDest = PicoDraw2FB + 328*(++num2) + 8;\r
\r
u += 6666;\r
\r