301 lines
7.1 KiB
C
301 lines
7.1 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "../emulibc/emulibc.h"
|
|
#include "../emulibc/waterboxcore.h"
|
|
#include "pico/pico.h"
|
|
#include "pico/pico_int.h"
|
|
#include "pico/cd/cdd.h"
|
|
|
|
void lprintf(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vprintf(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
int PicoCartResize(int newsize)
|
|
{
|
|
// TODO: change boards that use this to store their extra data elsewhere
|
|
abort();
|
|
return -1;
|
|
}
|
|
|
|
int PicoCdCheck(const char *fname_in, int *pregion)
|
|
{
|
|
uint8_t buff[2048];
|
|
CDReadSector(0, buff, 0);
|
|
int region;
|
|
switch (buff[0x20b])
|
|
{
|
|
case 0x64:
|
|
region = 8; // EU
|
|
printf("Detected CD region EU\n");
|
|
break;
|
|
case 0xa1:
|
|
region = 1; // JP
|
|
printf("Detected CD region JP\n");
|
|
break;
|
|
default:
|
|
region = 4; // US
|
|
printf("Detected CD region US\n");
|
|
break;
|
|
}
|
|
if (pregion)
|
|
*pregion = region;
|
|
|
|
return CIT_BIN;
|
|
}
|
|
|
|
static const char *GetBiosFilename(int *region, const char *cd_fname)
|
|
{
|
|
switch (*region)
|
|
{
|
|
case 8: // EU
|
|
return "cd.eu";
|
|
case 1: // JP
|
|
return "cd.jp";
|
|
default: // US?
|
|
return "cd.us";
|
|
}
|
|
}
|
|
|
|
pm_file *pm_open(const char *path)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
if (!f)
|
|
return NULL;
|
|
fseek(f, 0, SEEK_END);
|
|
pm_file *ret = calloc(1, sizeof(*ret));
|
|
ret->file = f;
|
|
ret->size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
ret->type = PMT_UNCOMPRESSED;
|
|
return ret;
|
|
}
|
|
size_t pm_read(void *ptr, size_t bytes, pm_file *stream)
|
|
{
|
|
return fread(ptr, 1, bytes, (FILE *)stream->file);
|
|
}
|
|
int pm_seek(pm_file *stream, long offset, int whence)
|
|
{
|
|
return fseek((FILE *)stream->file, offset, whence);
|
|
}
|
|
int pm_close(pm_file *fp)
|
|
{
|
|
int ret = fclose((FILE *)fp->file);
|
|
fp->file = NULL;
|
|
free(fp);
|
|
return ret;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
FrameInfo b;
|
|
uint32_t Buttons;
|
|
} MyFrameInfo;
|
|
|
|
static int video_start_line;
|
|
static int video_line_count;
|
|
static int video_width;
|
|
static uint16_t *video_buffer;
|
|
static int16_t *sound_buffer;
|
|
static MyFrameInfo *current_frame;
|
|
|
|
static void SoundCallback(int len)
|
|
{
|
|
current_frame->b.Samples = len / (2 * sizeof(int16_t));
|
|
memcpy(current_frame->b.SoundBuffer, sound_buffer, len);
|
|
}
|
|
|
|
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
|
{
|
|
video_start_line = start_line;
|
|
video_line_count = line_count;
|
|
video_width = is_32cols ? 256 : 320;
|
|
PicoDrawSetOutBuf(video_buffer, video_width * sizeof(uint16_t));
|
|
}
|
|
|
|
// "switch to 16bpp mode?"
|
|
void emu_32x_startup(void)
|
|
{
|
|
}
|
|
|
|
static const uint8_t *TryLoadBios(const char *name)
|
|
{
|
|
FILE *f = fopen(name, "rb");
|
|
if (!f)
|
|
return NULL;
|
|
fseek(f, 0, SEEK_END);
|
|
int size = ftell(f);
|
|
uint8_t *ret = alloc_sealed(size);
|
|
fseek(f, 0, SEEK_SET);
|
|
fread(ret, 1, size, f);
|
|
fclose(f);
|
|
return ret;
|
|
}
|
|
|
|
ECL_EXPORT int Init(int cd, int _32xPreinit, int regionAutoOrder, int regionOverride)
|
|
{
|
|
PicoAutoRgnOrder = regionAutoOrder;
|
|
PicoRegionOverride = regionOverride;
|
|
|
|
p32x_bios_g = TryLoadBios("32x.g");
|
|
p32x_bios_m = TryLoadBios("32x.m");
|
|
p32x_bios_s = TryLoadBios("32x.s");
|
|
|
|
PicoOpt = POPT_EN_FM | POPT_EN_PSG | POPT_EN_Z80 | POPT_EN_STEREO | POPT_ACC_SPRITES | POPT_DIS_32C_BORDER | POPT_EN_MCD_PCM | POPT_EN_MCD_CDDA | POPT_EN_MCD_GFX | POPT_EN_32X | POPT_EN_PWM | POPT_DIS_IDLE_DET;
|
|
|
|
PicoInit();
|
|
if (cd)
|
|
{
|
|
if (PicoLoadMedia(NULL, NULL, GetBiosFilename, NULL, PM_CD) != PM_CD)
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (PicoLoadMedia("romfile.md", NULL, NULL, NULL, PM_MD_CART) != PM_MD_CART)
|
|
return 0;
|
|
}
|
|
PicoLoopPrepare();
|
|
|
|
video_buffer = alloc_invisible(512 * 512 * sizeof(uint16_t));
|
|
sound_buffer = alloc_invisible(2048 * sizeof(int16_t));
|
|
PsndRate = 44100;
|
|
PsndOut = sound_buffer;
|
|
PicoWriteSound = SoundCallback;
|
|
|
|
PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN);
|
|
PicoSetInputDevice(1, PICO_INPUT_PAD_6BTN);
|
|
PsndRerate(0);
|
|
|
|
PicoDrawSetOutFormat(PDF_RGB555, 0); // TODO: what is "use_32x_line_mode"?
|
|
if (_32xPreinit)
|
|
{
|
|
// this is only needed so that the memory domains will show up on the memory domain list
|
|
// otherwise, 32x will run fine without it.
|
|
Pico32xMem = malloc(sizeof(*Pico32xMem));
|
|
}
|
|
|
|
PicoPower();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void Blit(void)
|
|
{
|
|
const uint16_t *src = video_buffer;
|
|
FrameInfo *f = ¤t_frame->b;
|
|
f->Width = video_width;
|
|
f->Height = video_line_count;
|
|
uint8_t *dst = (uint8_t *)f->VideoBuffer;
|
|
src += video_width * video_start_line;
|
|
|
|
for (int j = 0; j < video_line_count * video_width; j++)
|
|
{
|
|
uint16_t c = *src++;
|
|
*dst++ = c << 3 & 0xf8 | c >> 2 & 7;
|
|
*dst++ = c >> 3 & 0xfa | c >> 9 & 3;
|
|
*dst++ = c >> 8 & 0xf8 | c >> 13 & 7;
|
|
*dst++ = 0xff;
|
|
}
|
|
}
|
|
|
|
static uint32_t PrevButtons;
|
|
ECL_EXPORT void FrameAdvance(MyFrameInfo *f)
|
|
{
|
|
current_frame = f;
|
|
PicoInputWasRead = 0;
|
|
PicoPad[0] = f->Buttons & 0xfff;
|
|
PicoPad[1] = f->Buttons >> 12 & 0xfff;
|
|
if ((f->Buttons & 0x1000000) > (PrevButtons & 0x1000000))
|
|
PicoPower();
|
|
if ((f->Buttons & 0x2000000) > (PrevButtons & 0x2000000))
|
|
PicoReset();
|
|
PrevButtons = f->Buttons;
|
|
|
|
PicoFrame();
|
|
Blit();
|
|
f->b.Lagged = !PicoInputWasRead;
|
|
current_frame = NULL;
|
|
}
|
|
|
|
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
|
|
{
|
|
m[0].Data = Pico.ram;
|
|
m[0].Name = "68K RAM";
|
|
m[0].Size = 0x10000;
|
|
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED;
|
|
|
|
m[1].Data = Pico.vram;
|
|
m[1].Name = "VRAM";
|
|
m[1].Size = 0x10000;
|
|
m[1].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED;
|
|
|
|
m[2].Data = Pico.zram;
|
|
m[2].Name = "Z80 RAM";
|
|
m[2].Size = 0x2000;
|
|
m[2].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1;
|
|
|
|
m[3].Data = Pico.cram;
|
|
m[3].Name = "CRAM";
|
|
m[3].Size = 0x40;
|
|
m[3].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1;
|
|
|
|
m[4].Data = Pico.vsram;
|
|
m[4].Name = "VSRAM";
|
|
m[4].Size = 0x40;
|
|
m[4].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1;
|
|
|
|
m[5].Data = Pico.rom;
|
|
m[5].Name = "MD CART";
|
|
m[5].Size = Pico.romsize;
|
|
m[5].Flags = MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_SWAPPED | MEMORYAREA_FLAGS_YUGEENDIAN;
|
|
|
|
if (Pico32xMem)
|
|
{
|
|
m[6].Data = Pico32xMem->sdram;
|
|
m[6].Name = "32X RAM";
|
|
m[6].Size = 0x40000;
|
|
m[6].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED;
|
|
|
|
m[7].Data = Pico32xMem->dram;
|
|
m[7].Name = "32X FB";
|
|
m[7].Size = 0x40000;
|
|
m[7].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE2 | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_SWAPPED;
|
|
}
|
|
|
|
if (SRam.data != NULL)
|
|
{
|
|
m[8].Data = SRam.data;
|
|
m[8].Name = "SRAM";
|
|
m[8].Size = SRam.size;
|
|
m[8].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_SAVERAMMABLE;
|
|
}
|
|
}
|
|
|
|
ECL_EXPORT void SetInputCallback(void (*callback)(void))
|
|
{
|
|
PicoInputCallback = callback;
|
|
}
|
|
ECL_EXPORT void SetCDReadCallback(void (*callback)(int lba, void *dest, int audio))
|
|
{
|
|
CDReadSector = callback;
|
|
}
|
|
ECL_EXPORT int IsPal(void)
|
|
{
|
|
return Pico.m.pal;
|
|
}
|
|
ECL_EXPORT int Is32xActive(void)
|
|
{
|
|
return !!(PicoAHW & PAHW_32X);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
return 0;
|
|
}
|