X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ginge.git;a=blobdiff_plain;f=loader%2Femu.c;h=b425308dce4bafe792b52293116a64c959ae3ab6;hp=7e3ca5e5a5ce47e6cefbe2441692428a4b94e8a0;hb=0881206bcd3a0e2992373e7267d998324f4d3d90;hpb=86418a845b35b2bb08b611fa1a1d1eec05b924c9 diff --git a/loader/emu.c b/loader/emu.c index 7e3ca5e..b425308 100644 --- a/loader/emu.c +++ b/loader/emu.c @@ -1,6 +1,7 @@ // vim:shiftwidth=2:expandtab #include #include +#include #include #include #include @@ -15,89 +16,252 @@ //#define iolog printf #define iolog(...) +//#define segvlog printf +#define segvlog(...) typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; -static int memdev; -static volatile u16 *memregs, *blitter; +struct uppermem_block { + u32 addr; // physical + u32 size; + void *mem; + struct uppermem_block *next; +}; + +static struct uppermem_block *upper_mem; + +static struct { + u32 dstctrl; + u32 dstaddr; + u32 dststride; + u32 srcctrl; + u32 srcaddr; // + u32 srcstride; + u32 srcforcolor; + u32 srcbackcolor; + u32 patctrl; // + u32 patforcolor; + u32 patbackcolor; + u32 size; + u32 ctrl; // + u32 run; + u32 intc; + u32 srcfifo; +} blitter; + +#define SRCCTRL_INVIDEO (1 << 8) +#define SRCCTRL_SRCENB (1 << 7) +#define CTRL_TRANSPARENCYENB (1 << 11) + +static struct { + union { + u32 mlc_stl_eadr; + struct { + u16 mlc_stl_eadrl; + u16 mlc_stl_eadrh; + }; + }; +} mmsp2; +static u16 *host_screen; +static int host_stride; -static volatile void *translate_addr(u32 a, u32 *mask) + +static void memset16(void *dst, u32 pattern, int count) { - if ((a & 0xfff00000) == 0x7f000000) { - *mask = 0xffff; - return memregs; + u32 *dl; + u16 *d; + + d = (u16 *)((long)dst & ~1); + if ((long)d & 2) { + *d++ = pattern; + count--; } - if ((a & 0xfff00000) == 0x7f100000) { - *mask = 0xff; - return blitter; + dl = (void *)d; + pattern |= pattern << 16; + + while (count >= 2) { + *dl++ = pattern; + count -= 2; } - fprintf(stderr, "bad IO @ %08x\n", a); - abort(); + if (count) + *(u16 *)dl = pattern; } -static u32 xread8(u32 a) +static void blt_tr(void *dst, void *src, u32 trc, int w) { - volatile u8 *mem; - u32 mask; + u16 *d = (u16 *)((long)dst & ~1); + u16 *s = (u16 *)((long)src & ~1); + + // XXX: optimize + for (; w > 0; d++, s++, w--) + if (*s != trc) + *d = *s; +} + +#define dump_blitter() \ +{ \ + u32 *r = &blitter.dstctrl; \ + int i; \ + for (i = 0; i < 4*4; i++, r++) { \ + printf("%08x ", *r); \ + if ((i & 3) == 3) \ + printf("\n"); \ + } \ +} + +static void *upper_lookup(u32 addr, u8 **mem_end, int *stride_override) +{ + struct uppermem_block *ub; + + // maybe the screen? + if (mmsp2.mlc_stl_eadr <= addr && addr < mmsp2.mlc_stl_eadr + 320*240*2) { + host_screen = host_video_flip(); // HACK + *mem_end = (u8 *)host_screen + host_stride * 240; + *stride_override = host_stride; + return (u8 *)host_screen + addr - mmsp2.mlc_stl_eadr; + } + + for (ub = upper_mem; ub != NULL; ub = ub->next) { + if (ub->addr <= addr && addr < ub->addr + ub->size) { + *mem_end = (u8 *)ub->mem + ub->size; + return (u8 *)ub->mem + addr - ub->addr; + } + } + + return NULL; +} + +static void blitter_do(void) +{ + u8 *dst, *dste, *src = NULL, *srce = NULL; + int w, h, sstrd, dstrd; + u32 addr; + + w = blitter.size & 0x7ff; + h = (blitter.size >> 16) & 0x7ff; + sstrd = blitter.srcstride; + dstrd = blitter.dststride; + + // XXX: need to confirm this.. + addr = (blitter.dstaddr & ~3) | ((blitter.dstctrl & 0x1f) >> 3); + dst = upper_lookup(addr, &dste, &dstrd); + if (dst == NULL) + goto bad_blit; + + // XXX: assume fill if no SRCENB, but it could be pattern blit.. + if (blitter.srcctrl & SRCCTRL_SRCENB) { + if (!(blitter.srcctrl & SRCCTRL_INVIDEO)) + goto bad_blit; + + addr = (blitter.srcaddr & ~3) | ((blitter.srcctrl & 0x1f) >> 3); + src = upper_lookup(addr, &srce, &sstrd); + if (src == NULL) + goto bad_blit; + + if (src + sstrd * h > srce) { + printf("blit %08x->%08x %dx%d did not fit src\n", + blitter.srcaddr, blitter.dstaddr, w, h); + h = (srce - src) / sstrd; + } + } + + if (dst + dstrd * h > dste) { + printf("blit %08x->%08x %dx%d did not fit dst\n", + blitter.srcaddr, blitter.dstaddr, w, h); + h = (dste - dst) / dstrd; + } + + if (src != NULL) { + // copy + if (blitter.ctrl & CTRL_TRANSPARENCYENB) { + u32 trc = blitter.ctrl >> 16; + for (; h > 0; h--, dst += dstrd, src += sstrd) + blt_tr(dst, src, trc, w); + } + else { + for (; h > 0; h--, dst += dstrd, src += sstrd) + memcpy(dst, src, w * 2); + } + } + else { + // fill. Assume the pattern is cleared and bg color is used + u32 bgc = blitter.patbackcolor & 0xffff; + for (; h > 0; h--, dst += dstrd) + memset16(dst, bgc, w); + } + return; +bad_blit: + printf("blit %08x->%08x %dx%d translated to %p->%p\n", + blitter.srcaddr, blitter.dstaddr, w, h, src, dst); + dump_blitter(); +} + +static u32 xread8(u32 a) +{ iolog("r8 %08x\n", a); - mem = translate_addr(a, &mask); - return mem[a & mask]; + return 0; } static u32 xread16(u32 a) { - volatile u16 *mem; - u32 mask; - - //if ((a & 0xfff00000) == 0x7f100000) { static int a; a ^= ~1; return a & 0xffff; } +// if ((a & 0xfff00000) == 0x7f100000) { static int a; a ^= ~1; return a & 0xffff; } iolog("r16 %08x\n", a); - mem = translate_addr(a, &mask); - return mem[(a & mask) / 2]; + return 0; } static u32 xread32(u32 a) { - volatile u32 *mem; - u32 mask; - - //if ((a & 0xfff00000) == 0x7f100000) { static int a; a ^= ~1; return a; } + u32 d = 0; + if ((a & 0xfff00000) == 0x7f100000) { + u32 *bl = &blitter.dstctrl; + a &= 0xfff; + if (a < 0x40) + d = bl[a / 4]; + if (a == 0x34) + d = 0; // not busy + } iolog("r32 %08x\n", a); - mem = translate_addr(a, &mask); - return mem[(a & mask) / 4]; + return d; } static void xwrite8(u32 a, u32 d) { - volatile u8 *mem; - u32 mask; - iolog("w8 %08x %08x\n", a, d); - mem = translate_addr(a, &mask); - mem[a & mask] = d; } static void xwrite16(u32 a, u32 d) { - volatile u16 *mem; - u32 mask; - iolog("w16 %08x %08x\n", a, d); - mem = translate_addr(a, &mask); - mem[(a & mask) / 2] = d; + if ((a & 0xfff00000) == 0x7f000000) { + a &= 0xffff; + switch (a) { + case 0x2912: mmsp2.mlc_stl_eadrl = d; break; + case 0x2914: mmsp2.mlc_stl_eadrh = d; break; + } + //printf("w16 %08x %08x\n", a, d); + } } static void xwrite32(u32 a, u32 d) { - volatile u32 *mem; - u32 mask; - iolog("w32 %08x %08x\n", a, d); - mem = translate_addr(a, &mask); - mem[(a & mask) / 4] = d; + if ((a & 0xfff00000) == 0x7f000000) { + printf("w32 %08x %08x\n", a, d); + return; + } + if ((a & 0xfff00000) == 0x7f100000) { + u32 *bl = &blitter.dstctrl; + a &= 0xfff; + if (a < 0x40) + bl[a / 4] = d; + if (a == 0x34 && (d & 1)) + blitter_do(); + return; + } } #define BIT_SET(v, b) (v & (1 << (b))) @@ -266,7 +430,7 @@ static void segv_sigaction(int num, siginfo_t *info, void *ctx) signal(num, SIG_DFL); raise(num); } - printf("segv %d %p @ %08x\n", info->si_code, info->si_addr, regs[15]); + segvlog("segv %d %p @ %08x\n", info->si_code, info->si_addr, regs[15]); // spit PC and op pc_ptr = g_code_ptr++; @@ -296,7 +460,7 @@ static void segv_sigaction(int num, siginfo_t *info, void *ctx) sys_cacheflush(g_linkpage, g_code_ptr); lp_size = (char *)g_code_ptr - (char *)g_linkpage; - printf("code #%d %d/%d\n", g_linkpage_count, lp_size, LINKPAGE_SIZE); + segvlog("code #%d %d/%d\n", g_linkpage_count, lp_size, LINKPAGE_SIZE); if (lp_size + 13*4 > LINKPAGE_SIZE) { g_linkpage_count++; @@ -331,36 +495,81 @@ void emu_init(void *map_bottom) printf("linkpages @ %p\n", g_linkpage); init_linkpage(); - memdev = open("/dev/mem", O_RDWR); - memregs = mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000); - blitter = mmap(NULL, 0x100, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xe0020000); - //blitter = mmap(NULL, 0x100, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - printf("mapped %d %p %p\n", memdev, memregs, blitter); + // host stuff + host_screen = host_video_init(&host_stride); + if (host_screen == NULL) { + printf("can't alloc screen\n"); + exit(1); + } +} + +int emu_read_gpiodev(void *buf, int count) +{ + unsigned int btns; + + if (count < 4) { + printf("gpiodev read %d?\n", count); + return -1; + } + + btns = host_read_btns(); + memcpy(buf, &btns, 4); + return 4; } void *emu_mmap_dev(unsigned int length, int prot, int flags, unsigned int offset) { + struct uppermem_block *umem; char name[32]; int fd; + // SoC regs if ((offset & ~0xffff) == 0xc0000000) { return mmap((void *)0x7f000000, length, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_NORESERVE, -1, 0); } + // blitter if ((offset & ~0xffff) == 0xe0020000) { return mmap((void *)0x7f100000, length, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_NORESERVE, -1, 0); } - // pass through - if ((offset & 0xfe000000) == 0x02000000) - return mmap(NULL, length, prot, flags, memdev, offset); + // upper mem + if ((offset & 0xfe000000) != 0x02000000) + printf("unexpected devmem mmap @ %08x\n", offset); + + // return mmap(NULL, length, prot, flags, memdev, offset); + + umem = calloc(1, sizeof(*umem)); + if (umem == NULL) { + printf("OOM\n"); + return MAP_FAILED; + } + + umem->addr = offset; + umem->size = length; + umem->mem = mmap(NULL, length, prot, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (umem->mem != MAP_FAILED) + goto done; + printf("upper mem @ %08x %d mmap fail, trying backing file\n", offset, length); sprintf(name, "m%08x", offset); fd = open(name, O_CREAT|O_RDWR, 0644); lseek(fd, length - 1, SEEK_SET); name[0] = 0; write(fd, name, 1); - return mmap(NULL, length, prot, MAP_SHARED, fd, 0); + umem->mem = mmap(NULL, length, prot, MAP_SHARED, fd, 0); + if (umem->mem == MAP_FAILED) { + printf("failed, giving up\n"); + close(fd); + free(umem); + return MAP_FAILED; + } + +done: + printf("upper mem @ %08x %d\n", offset, length); + umem->next = upper_mem; + upper_mem = umem; + return umem->mem; }