#include #include #include #include #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; }