ref: a4fb5d06d406d9a21fcc767d81e870603d3b397a
parent: b958a4826fe639704e81351a844bb947c799839e
author: Jean-André Santoni <jean.andre.santoni@gmail.com>
date: Sat Mar 7 19:46:51 EST 2026
eui
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,62 @@
+#ifndef DAT_H
+#define DAT_H
+
+#include "psx/p9.h"
+#include <draw.h>
+#include <thread.h>
+#include <keyboard.h>
+
+#include "eui.h"
+#include "psx/log.h"
+#include "psx/psx.h"
+#include "psx/dev/cdrom/cdrom.h"
+#include "psx/dev/gpu.h"
+#include "psx/dev/pad.h"
+#include "psx/dev/timer.h"
+#include "psx/input/sda.h"
+
+typedef struct Emu Emu;
+
+struct Emu {+ psx_t *psx;
+ psx_pad_t *pad;
+ u64int prevkeys;
+};
+
+enum {+ Vwdx = 640,
+ Vwdy = 480,
+};
+
+enum {+ KeyCross = 1 << 0,
+ KeySquare = 1 << 1,
+ KeyTriangle = 1 << 2,
+ KeyCircle = 1 << 3,
+ KeyStart = 1 << 4,
+ KeySelect = 1 << 5,
+ KeyUp = 1 << 6,
+ KeyDown = 1 << 7,
+ KeyLeft = 1 << 8,
+ KeyRight = 1 << 9,
+ KeyL1 = 1 << 10,
+ KeyR1 = 1 << 11,
+ KeyL2 = 1 << 12,
+ KeyR2 = 1 << 13,
+ KeyL3 = 1 << 14,
+ KeyR3 = 1 << 15,
+ KeyAnalog = 1 << 16,
+};
+
+extern Emu emu;
+
+/* Frontend glue uses these directly. Keep explicit declarations local to psxe UI. */
+void psx_pad_button_press(psx_pad_t*, int, uint32_t);
+void psx_pad_button_release(psx_pad_t*, int, uint32_t);
+void psx_pad_attach_joy(psx_pad_t*, int, psx_input_t*);
+int psx_pad_attach_mcd(psx_pad_t*, int, const char*);
+psx_spu_t* psx_spu_create(void);
+void psx_spu_init(psx_spu_t*, psx_ic_t*);
+void psx_spu_destroy(psx_spu_t*);
+
+#endif
--- /dev/null
+++ b/eui.c
@@ -1,0 +1,415 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include "eui.h"
+
+typedef struct Kfn Kfn;
+
+u64int keys, keys2;
+int trace, paused;
+int savereq, loadreq;
+QLock pauselock;
+int scale, fixscale, warp10;
+uchar *pic;
+Rectangle picr;
+Mousectl *mc;
+Image *bg;
+
+static int profile, framestep;
+static int vwdx, vwdy, vwbpp;
+static ulong vwchan;
+static Image *fb;
+static Channel *conv, *sync[2];
+static uchar *screenconv[2], *backfb;
+static int screenconvi;
+
+struct Kfn{+ Rune r;
+ int k;
+ char joyk[16];
+ void(*fn)(void);
+ Kfn *n;
+};
+static Kfn kfn, kkn;
+static int ax0, ax1;
+
+void *
+emalloc(ulong sz)
+{+ void *v;
+
+ v = mallocz(sz, 1);
+ if(v == nil)
+ sysfatal("malloc: %r");+ setmalloctag(v, getcallerpc(&sz));
+ return v;
+}
+
+Image *
+eallocimage(Rectangle r, ulong chan, int repl, ulong col)
+{+ Image *i;
+
+ if((i = allocimage(display, r, chan, repl, col)) == nil)
+ sysfatal("allocimage: %r");+ return i;
+}
+
+static void
+joyproc(void *)
+{+ char buf[64], *s, *down[9];
+ int n, k, j;
+ Kfn *kp;
+
+ j = 1;
+
+ for(;;){+ n = read(0, buf, sizeof(buf));
+ if(n <= 0)
+ sysfatal("read: %r");+ buf[n-1] = 0;
+ n = getfields(buf, down, nelem(down), 0, " ");
+ k = 0;
+ for(n--; n >= 0; n--){+ s = down[n];
+ if(strcmp(s, "joy1") == 0)
+ j = 1;
+ else if(strcmp(s, "joy2") == 0)
+ j = 2;
+ for(kp=kkn.n; kp!=nil; kp=kp->n){+ if(strcmp(kp->joyk, s) == 0)
+ k |= kp->k;
+ }
+ }
+ if(j == 2)
+ keys2 = k;
+ else
+ keys = k;
+ }
+}
+
+static void
+keyproc(void *)
+{+ int fd, n, k;
+ static char buf[256];
+ char *s;
+ Rune r;
+ Kfn *kp;
+
+ fd = open("/dev/kbd", OREAD);+ if(fd < 0)
+ sysfatal("open: %r");+ for(;;){+ if(buf[0] != 0){+ n = strlen(buf)+1;
+ memmove(buf, buf+n, sizeof(buf)-n);
+ }
+ if(buf[0] == 0){+ n = read(fd, buf, sizeof(buf)-1);
+ if(n <= 0)
+ sysfatal("read /dev/kbd: %r");+ buf[n-1] = 0;
+ buf[n] = 0;
+ }
+ if(buf[0] == 'c'){+ if(utfrune(buf, Kdel)){+ close(fd);
+ threadexitsall(nil);
+ }
+ if(utfrune(buf, KF|5))
+ savereq = 1;
+ if(utfrune(buf, KF|6))
+ loadreq = 1;
+ if(utfrune(buf, KF|12))
+ profile ^= 1;
+ if(utfrune(buf, 't'))
+ trace = !trace;
+ for(kp=kfn.n; kp!=nil; kp=kp->n){+ if(utfrune(buf, kp->r))
+ kp->fn();
+ }
+ }
+ if(buf[0] != 'k' && buf[0] != 'K')
+ continue;
+ s = buf + 1;
+ k = 0;
+ while(*s != 0){+ s += chartorune(&r, s);
+ switch(r){+ case Kdel: close(fd); threadexitsall(nil);
+ case Kesc:
+ if(paused)
+ qunlock(&pauselock);
+ else
+ qlock(&pauselock);
+ paused = !paused;
+ break;
+ case KF|1:
+ if(paused){+ qunlock(&pauselock);
+ paused=0;
+ }
+ framestep = !framestep;
+ break;
+ case '`':
+ warp10 = !warp10;
+ break;
+ }
+ for(kp=kkn.n; kp!=nil; kp=kp->n)
+ if(kp->r == r){+ k |= kp->k;
+ break;
+ }
+ }
+ if((k & ax0) == ax0)
+ k &= ~ax0;
+ if((k & ax1) == ax1)
+ k &= ~ax1;
+ keys = k;
+ }
+}
+
+static void
+timing(void)
+{+ static int fcount;
+ static vlong old;
+ static char buf[32];
+ vlong new;
+
+ if(++fcount == 60)
+ fcount = 0;
+ else
+ return;
+ new = nsec();
+ if(new != old)
+ sprint(buf, "%6.2f%%", 1e11 / (new - old));
+ else
+ buf[0] = 0;
+ draw(screen, rectaddpt(Rect(10, 10, vwdx-40, 30), screen->r.min), bg, nil, ZP);
+ string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
+ old = nsec();
+}
+
+static void
+screeninit(void)
+{+ Point p;
+
+ send(sync[0], nil);
+ if(!fixscale){+ scale = Dx(screen->r) / vwdx;
+ if(Dy(screen->r) / vwdy < scale)
+ scale = Dy(screen->r) / vwdy;
+ }
+ if(scale <= 0)
+ scale = 1;
+ else if(scale > 16)
+ scale = 16;
+ p = divpt(addpt(screen->r.min, screen->r.max), 2);
+ picr = Rpt(subpt(p, Pt(scale * vwdx/2, scale * vwdy/2)),
+ addpt(p, Pt(scale * vwdx/2, scale * vwdy/2)));
+ freeimage(fb);
+ fb = eallocimage(Rect(0, 0, scale * vwdx, scale > 1 ? 1 : vwdy),
+ vwchan, scale > 1, 0);
+ free(backfb);
+ if(scale > 1)
+ backfb = emalloc(vwdx * vwbpp * scale);
+ else
+ backfb = nil;
+ draw(screen, screen->r, bg, nil, ZP);
+ recv(sync[1], nil);
+}
+
+void
+flushmouse(int discard)
+{+ Mouse m;
+
+ if(nbrecvul(mc->resizec) > 0){+ send(sync[0], nil);
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");+ recv(sync[1], nil);
+ screeninit();
+ }
+ if(discard)
+ while(nbrecv(mc->c, &m) > 0)
+ ;
+}
+
+static void
+screenproc(void*)
+{+ uchar *p;
+ enum { Draw, Sync1, Sync2 };+ Alt alts[] = {+ [Draw] {.c = conv, .v = &p, .op = CHANRCV},+ [Sync1] {.c = sync[0], .op = CHANRCV},+ [Sync2] {.c = sync[1], .op = CHANNOP},+ {.op = CHANEND},+ };
+
+ for(;;) switch(alt(alts)){+ case Draw:
+ if(scale == 1){+ loadimage(fb, fb->r, p, vwdx * vwdy * vwbpp);
+ draw(screen, picr, fb, nil, ZP);
+ } else {+ Rectangle r;
+ int w, x;
+
+ r = picr;
+ w = vwdx * vwbpp * scale;
+ while(r.min.y < picr.max.y){+ switch(vwbpp){+ case 4: {+ u32int *d = (u32int *)backfb, *e, s;
+ for(x=0; x<vwdx; x++){+ s = *(u32int *)p;
+ p += vwbpp;
+ e = d + scale;
+ while(d < e)
+ *d++ = s;
+ }
+ break;
+ } case 2: {+ u16int *d = (u16int *)backfb, *e, s;
+ for(x=0; x<vwdx; x++){+ s = *(u16int *)p;
+ p += vwbpp;
+ e = d + scale;
+ while(d < e)
+ *d++ = s;
+ }
+ break;
+ } case 1: {+ u8int *d = (u8int *)backfb, *e, s;
+ for(x=0; x<vwdx; x++){+ s = *(u8int *)p;
+ p += vwbpp;
+ e = d + scale;
+ while(d < e)
+ *d++ = s;
+ }
+ break;
+ }}
+ loadimage(fb, fb->r, backfb, w);
+ r.max.y = r.min.y+scale;
+ draw(screen, r, fb, nil, ZP);
+ r.min.y = r.max.y;
+ }
+ }
+ flushimage(display, 1);
+ break;
+ case Sync1:
+ alts[Draw].op = CHANNOP;
+ alts[Sync1].op = CHANNOP;
+ alts[Sync2].op = CHANSND;
+ break;
+ case Sync2:
+ alts[Draw].op = CHANRCV;
+ alts[Sync1].op = CHANRCV;
+ alts[Sync2].op = CHANNOP;
+ break;
+ }
+}
+
+void
+flushscreen(void)
+{+ memmove(screenconv[screenconvi], pic, vwdx * vwdy * vwbpp);
+ if(sendp(conv, screenconv[screenconvi]) > 0)
+ screenconvi = (screenconvi + 1) % 2;
+ if(profile)
+ timing();
+}
+
+void
+flushaudio(int (*audioout)(void))
+{+ static vlong old, delta;
+ vlong new, diff;
+
+ if(audioout == nil || audioout() < 0 && !warp10){+ new = nsec();
+ diff = 0;
+ if(old != 0){+ diff = BILLION/60 - (new - old) - delta;
+ if(diff >= MILLION)
+ sleep(diff/MILLION);
+ }
+ old = nsec();
+ if(diff > 0){+ diff = (old - new) - (diff / MILLION) * MILLION;
+ delta += (diff - delta) / 100;
+ }
+ }
+ if(framestep){+ paused = 1;
+ qlock(&pauselock);
+ framestep = 0;
+ }
+}
+
+void
+regkeyfn(Rune r, void (*fn)(void))
+{+ Kfn *kp;
+
+ for(kp=&kfn; kp->n!=nil; kp=kp->n)
+ ;
+ kp->n = emalloc(sizeof *kp);
+ kp->n->r = r;
+ kp->n->fn = fn;
+}
+
+void
+regkey(char *joyk, Rune r, int k)
+{+ Kfn *kp;
+
+ for(kp=&kkn; kp->n!=nil; kp=kp->n)
+ ;
+ kp->n = emalloc(sizeof *kp);
+ strncpy(kp->n->joyk, joyk, sizeof(kp->n->joyk)-1);
+ if(strcmp(joyk, "up") == 0 || strcmp(joyk, "down") == 0)
+ ax0 |= k;
+ if(strcmp(joyk, "left") == 0 || strcmp(joyk, "right") == 0)
+ ax1 |= k;
+ kp->n->r = r;
+ kp->n->k = k;
+}
+
+void
+initemu(int dx, int dy, int bpp, ulong chan, int dokey, void(*kproc)(void*))
+{+ vwdx = dx;
+ vwdy = dy;
+ vwchan = chan;
+ vwbpp = bpp;
+ if(initdraw(nil, nil, nil) < 0)
+ sysfatal("initdraw: %r");+ mc = initmouse(nil, screen);
+ if(mc == nil)
+ sysfatal("initmouse: %r");+ if(dokey)
+ proccreate(kproc != nil ? kproc : keyproc, nil, mainstacksize);
+ if(kproc == nil)
+ proccreate(joyproc, nil, mainstacksize);
+ bg = eallocimage(Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+ scale = fixscale;
+ conv = chancreate(sizeof(uchar*), 0);
+ sync[0] = chancreate(1, 0);
+ sync[1] = chancreate(1, 0);
+ proccreate(screenproc, nil, mainstacksize);
+ pic = emalloc(vwdx * vwdy * vwbpp);
+ screenconv[0] = emalloc(vwdx * vwdy * vwbpp);
+ screenconv[1] = emalloc(vwdx * vwdy * vwbpp);
+ screeninit();
+}
--- /dev/null
+++ b/eui.h
@@ -1,0 +1,19 @@
+enum{+ MILLION = 1000000,
+ BILLION = 1000000000,
+};
+
+extern u64int keys, keys2;
+extern int trace, paused;
+extern int savereq, loadreq;
+extern QLock pauselock;
+extern int scale, fixscale, warp10;
+extern uchar *pic;
+
+void* emalloc(ulong);
+void flushmouse(int);
+void flushscreen(void);
+void flushaudio(int(*)(void));
+void regkeyfn(Rune, void(*)(void));
+void regkey(char*, Rune, int);
+void initemu(int, int, int, ulong, int, void(*)(void*));
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,14 @@
+#ifndef FNS_H
+#define FNS_H
+
+typedef struct psx_gpu_t psx_gpu_t;
+
+int audioout(void);
+void bindkeys(void);
+void blitframe(void);
+void flush(void);
+void process_inputs(void);
+void psxe_gpu_vblank_event_cb(psx_gpu_t*);
+void usage(void);
+
+#endif
--- a/mkfile
+++ b/mkfile
@@ -1,46 +1,16 @@
</$objtype/mkfile
-# Core-only build for 9front/native ports.
-# Excludes frontend/ (SDL UI/audio loop) and builds reusable emulator core.
-LIB=libpsxe_core.a
+BIN=/$objtype/bin/games
+TARG=psxe
CFLAGS=$CFLAGS -I. -Ipsx
HFILES=\
- psx/bus.h\
- psx/bus_init.h\
- psx/config.h\
- psx/cpu.h\
- psx/cpu_debug.h\
- psx/exe.h\
- psx/log.h\
- psx/psx.h\
- psx/input/guncon.h\
- psx/input/sda.h\
- psx/dev/bios.h\
- psx/dev/dma.h\
- psx/dev/exp1.h\
- psx/dev/exp2.h\
- psx/dev/gpu.h\
- psx/dev/ic.h\
- psx/dev/input.h\
- psx/dev/mc1.h\
- psx/dev/mc2.h\
- psx/dev/mc3.h\
- psx/dev/mcd.h\
- psx/dev/mdec.h\
- psx/dev/pad.h\
- psx/dev/ram.h\
- psx/dev/scratchpad.h\
- psx/dev/spu.h\
- psx/dev/timer.h\
- psx/dev/xa.h\
- psx/dev/cdrom/cdrom.h\
- psx/dev/cdrom/cue.h\
- psx/dev/cdrom/disc.h\
- psx/dev/cdrom/list.h\
- psx/dev/cdrom/queue.h\
+ dat.h\
+ fns.h\
OFILES=\
+ psxe.$O\
+ eui.$O\
bus.$O\
config.$O\
cpu.$O\
@@ -75,15 +45,13 @@
list.$O\
queue.$O\
-default:V: $LIB
+</sys/src/cmd/mkone
%.$O: psx/%.c
- $CC $CFLAGS -o $target $prereq
+ $CC $CFLAGS psx/$stem.c
%.$O: psx/input/%.c
- $CC $CFLAGS -o $target $prereq
+ $CC $CFLAGS psx/input/$stem.c
%.$O: psx/dev/%.c
- $CC $CFLAGS -o $target $prereq
+ $CC $CFLAGS psx/dev/$stem.c
%.$O: psx/dev/cdrom/%.c
- $CC $CFLAGS -o $target $prereq
-
-</sys/src/cmd/mksyslib
+ $CC $CFLAGS psx/dev/cdrom/$stem.c
--- a/psx/bus.c
+++ b/psx/bus.c
@@ -14,58 +14,64 @@
#include "dev/ic.h"
#include "dev/scratchpad.h"
#include "dev/gpu.h"
+#include "dev/spu.h"
+#include "dev/timer.h"
+#include "dev/pad.h"
+#include "dev/mdec.h"
#include "log.h"
-/*
- * 6c struggles with the full SPU header in this TU; bus only needs
- * the MMIO prefix fields and read/write entry points.
- */
-struct psx_spu_t {- uint32_t bus_delay;
- uint32_t io_base, io_size;
-};
-uint32_t psx_spu_read32(struct psx_spu_t*, uint32_t);
-uint16_t psx_spu_read16(struct psx_spu_t*, uint32_t);
-uint8_t psx_spu_read8(struct psx_spu_t*, uint32_t);
-void psx_spu_write32(struct psx_spu_t*, uint32_t, uint32_t);
-void psx_spu_write16(struct psx_spu_t*, uint32_t, uint16_t);
-void psx_spu_write8(struct psx_spu_t*, uint32_t, uint8_t);
+/* Keep explicit MMIO entrypoint declarations for 6c in this TU. */
+uint32_t psx_spu_read32(psx_spu_t*, uint32_t);
+uint16_t psx_spu_read16(psx_spu_t*, uint32_t);
+uint8_t psx_spu_read8(psx_spu_t*, uint32_t);
+void psx_spu_write32(psx_spu_t*, uint32_t, uint32_t);
+void psx_spu_write16(psx_spu_t*, uint32_t, uint16_t);
+void psx_spu_write8(psx_spu_t*, uint32_t, uint8_t);
+uint32_t psx_timer_read32(psx_timer_t*, uint32_t);
+uint16_t psx_timer_read16(psx_timer_t*, uint32_t);
+uint8_t psx_timer_read8(psx_timer_t*, uint32_t);
+void psx_timer_write32(psx_timer_t*, uint32_t, uint32_t);
+void psx_timer_write16(psx_timer_t*, uint32_t, uint16_t);
+void psx_timer_write8(psx_timer_t*, uint32_t, uint8_t);
+uint32_t psx_pad_read32(psx_pad_t*, uint32_t);
+uint16_t psx_pad_read16(psx_pad_t*, uint32_t);
+uint8_t psx_pad_read8(psx_pad_t*, uint32_t);
+void psx_pad_write32(psx_pad_t*, uint32_t, uint32_t);
+void psx_pad_write16(psx_pad_t*, uint32_t, uint16_t);
+void psx_pad_write8(psx_pad_t*, uint32_t, uint8_t);
+uint32_t psx_mdec_read32(psx_mdec_t*, uint32_t);
+uint16_t psx_mdec_read16(psx_mdec_t*, uint32_t);
+uint8_t psx_mdec_read8(psx_mdec_t*, uint32_t);
+void psx_mdec_write32(psx_mdec_t*, uint32_t, uint32_t);
+void psx_mdec_write16(psx_mdec_t*, uint32_t, uint16_t);
+void psx_mdec_write8(psx_mdec_t*, uint32_t, uint8_t);
+
+#define RANGE(v, s, e) ((v >= s) && (v < e))
-struct psx_timer_t {+typedef struct psx_bus_iomap_t {uint32_t bus_delay;
uint32_t io_base, io_size;
-};
-uint32_t psx_timer_read32(struct psx_timer_t*, uint32_t);
-uint16_t psx_timer_read16(struct psx_timer_t*, uint32_t);
-uint8_t psx_timer_read8(struct psx_timer_t*, uint32_t);
-void psx_timer_write32(struct psx_timer_t*, uint32_t, uint32_t);
-void psx_timer_write16(struct psx_timer_t*, uint32_t, uint16_t);
-void psx_timer_write8(struct psx_timer_t*, uint32_t, uint8_t);
+} psx_bus_iomap_t;
-struct psx_pad_t {- uint32_t bus_delay;
- uint32_t io_base, io_size;
-};
-uint32_t psx_pad_read32(struct psx_pad_t*, uint32_t);
-uint16_t psx_pad_read16(struct psx_pad_t*, uint32_t);
-uint8_t psx_pad_read8(struct psx_pad_t*, uint32_t);
-void psx_pad_write32(struct psx_pad_t*, uint32_t, uint32_t);
-void psx_pad_write16(struct psx_pad_t*, uint32_t, uint16_t);
-void psx_pad_write8(struct psx_pad_t*, uint32_t, uint8_t);
+static int
+bus_probe(void *dev, uint32_t addr, uint32_t *off, uint32_t *cyc)
+{+ psx_bus_iomap_t *h;
-struct psx_mdec_t {- uint32_t bus_delay;
- uint32_t io_base, io_size;
-};
-uint32_t psx_mdec_read32(struct psx_mdec_t*, uint32_t);
-uint16_t psx_mdec_read16(struct psx_mdec_t*, uint32_t);
-uint8_t psx_mdec_read8(struct psx_mdec_t*, uint32_t);
-void psx_mdec_write32(struct psx_mdec_t*, uint32_t, uint32_t);
-void psx_mdec_write16(struct psx_mdec_t*, uint32_t, uint16_t);
-void psx_mdec_write8(struct psx_mdec_t*, uint32_t, uint8_t);
+ if (dev == nil)
+ return 0;
+
+ h = (psx_bus_iomap_t*)dev;
+
+ if (!RANGE(addr, h->io_base, (h->io_base + h->io_size)))
+ return 0;
+
+ *off = addr - h->io_base;
+ *cyc = h->bus_delay;
+
+ return 1;
+}
-#define RANGE(v, s, e) ((v >= s) && (v < e))
-
const uint32_t g_psx_bus_region_mask_table[] = {
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0x7fffffff, 0x1fffffff, 0xffffffff, 0xffffffff
@@ -84,17 +90,21 @@
free(bus);
}
-#define HANDLE_READ_OP(dev, fn) \
- if (RANGE(addr, bus->dev->io_base, (bus->dev->io_base + bus->dev->io_size))) { \- bus->access_cycles = bus->dev->bus_delay; \
- return fn(bus->dev, addr - bus->dev->io_base); \
- }
-#define HANDLE_WRITE_OP(dev, fn) \
- if (RANGE(addr, bus->dev->io_base, (bus->dev->io_base + bus->dev->io_size))) { \- bus->access_cycles = bus->dev->bus_delay; \
- fn(bus->dev, addr - bus->dev->io_base, value); \
+#define HANDLE_READ_OP(dev, fn) do { \+ uint32_t off, cyc; \
+ if (bus_probe(bus->dev, addr, &off, &cyc)) { \+ bus->access_cycles = cyc; \
+ return fn(bus->dev, off); \
+ } \
+} while (0)
+#define HANDLE_WRITE_OP(dev, fn) do { \+ uint32_t off, cyc; \
+ if (bus_probe(bus->dev, addr, &off, &cyc)) { \+ bus->access_cycles = cyc; \
+ fn(bus->dev, off, value); \
return; \
- }
+ } \
+} while (0)
uint32_t psx_bus_read32(psx_bus_t* bus, uint32_t addr) {
uint32_t vaddr = addr;
--- a/psx/bus.h
+++ b/psx/bus.h
@@ -1,11 +1,8 @@
-#ifndef BUS_H
-#define BUS_H
-
-#include "p9.h"
-
-struct psx_bus_t;
+#ifndef PSX_BUS_H
+#define PSX_BUS_H
-typedef struct psx_bus_t psx_bus_t;
+#include "p9.h"
+#include "bus_init.h"
psx_bus_t* psx_bus_create(void);
void psx_bus_init(psx_bus_t*);
--- a/psx/bus_init.h
+++ b/psx/bus_init.h
@@ -1,5 +1,5 @@
-#ifndef BUS_INIT_H
-#define BUS_INIT_H
+#ifndef PSX_BUS_INIT_H
+#define PSX_BUS_INIT_H
#include "p9.h"
@@ -36,6 +36,8 @@
typedef struct psx_cdrom_t psx_cdrom_t;
typedef struct psx_pad_t psx_pad_t;
typedef struct psx_mdec_t psx_mdec_t;
+
+typedef struct psx_bus_t psx_bus_t;
struct psx_bus_t {struct psx_bios_t* bios;
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -1,12 +1,12 @@
-#include "cpu.h"
-#include "bus.h"
-#include "log.h"
-
-#include "p9.h"
-
-#include "cpu_debug.h"
-
-static const uint32_t g_psx_cpu_cop0_write_mask_table[] = {
+#include "cpu.h"
+#include "bus.h"
+#include "log.h"
+
+#include "p9.h"
+
+#include "cpu_debug.h"
+
+static const uint32_t g_psx_cpu_cop0_write_mask_table[] = {0x00000000, // cop0r0 - N/A
0x00000000, // cop0r1 - N/A
0x00000000, // cop0r2 - N/A
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -1,5 +1,5 @@
-#ifndef CPU_H
-#define CPU_H
+#ifndef PSX_CPU_H
+#define PSX_CPU_H
#include "p9.h"
--- a/psx/exe.h
+++ b/psx/exe.h
@@ -1,5 +1,5 @@
-#ifndef EXE_H
-#define EXE_H
+#ifndef PSX_EXE_H
+#define PSX_EXE_H
#include "p9.h"
@@ -48,4 +48,4 @@
int psx_exe_load(psx_cpu_t*, const char*);
-#endif
\ No newline at end of file
+#endif
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -1,4 +1,5 @@
#include "psx.h"
+#include "dat.h"
#include "dev/bios.h"
#include "dev/ram.h"
#include "dev/dma.h"
@@ -16,16 +17,7 @@
#include "dev/pad.h"
#include "dev/mdec.h"
-/* Keep explicit prototypes for 6c in this TU. */
-psx_bios_t* psx_bios_create(void);
-void psx_bios_init(psx_bios_t*);
-int psx_bios_load(psx_bios_t*, const char*);
-void psx_bios_destroy(psx_bios_t*);
-psx_spu_t* psx_spu_create(void);
-void psx_spu_init(psx_spu_t*, psx_ic_t*);
-void psx_spu_destroy(psx_spu_t*);
-
-psx_t* psx_create(void) {
+psx_t* psx_create(void) {return (psx_t*)malloc(sizeof(psx_t));
}
--- a/psx/psx.h
+++ b/psx/psx.h
@@ -1,5 +1,5 @@
-#ifndef PSX_H
-#define PSX_H
+#ifndef PSX_PSX_H
+#define PSX_PSX_H
#include "cpu.h"
#include "log.h"
@@ -14,10 +14,10 @@
#define PSXE_COMMIT STR(REP_COMMIT_HASH)
#define PSXE_BUILD_OS STR(OS_INFO)
-typedef struct {
- psx_bios_t* bios;
- psx_ram_t* ram;
- psx_dma_t* dma;
+typedef struct psx_t {+ psx_bios_t* bios;
+ psx_ram_t* ram;
+ psx_dma_t* dma;
psx_exp1_t* exp1;
psx_exp2_t* exp2;
psx_mc1_t* mc1;
@@ -30,10 +30,10 @@
psx_bus_t* bus;
psx_cpu_t* cpu;
psx_timer_t* timer;
- psx_cdrom_t* cdrom;
- psx_pad_t* pad;
- psx_mdec_t* mdec;
-} psx_t;
+ psx_cdrom_t* cdrom;
+ psx_pad_t* pad;
+ psx_mdec_t* mdec;
+} psx_t;
psx_t* psx_create(void);
int psx_init(psx_t*, const char*, const char*);
@@ -76,4 +76,4 @@
psx_cpu_t* psx_get_cpu(psx_t*);
void psx_destroy(psx_t*);
-#endif
\ No newline at end of file
+#endif
--- /dev/null
+++ b/psxe.c
@@ -1,0 +1,254 @@
+#include "dat.h"
+#include "fns.h"
+
+Emu emu;
+
+static u32int
+bgr555toxrgb32(u16int c)
+{+ u32int r, g, b;
+
+ r = (c >> 0) & 0x1f;
+ g = (c >> 5) & 0x1f;
+ b = (c >> 10) & 0x1f;
+
+ r = (r << 3) | (r >> 2);
+ g = (g << 3) | (g >> 2);
+ b = (b << 3) | (b >> 2);
+
+ return 0xff000000 | (r << 16) | (g << 8) | b;
+}
+
+static void
+button_edge(u64int now, u64int bit, u32int mask)
+{+ if(((now ^ emu.prevkeys) & bit) == 0)
+ return;
+
+ if((now & bit) != 0)
+ psx_pad_button_press(emu.pad, 0, mask);
+ else
+ psx_pad_button_release(emu.pad, 0, mask);
+}
+
+void
+process_inputs(void)
+{+ u64int now;
+
+ now = keys;
+
+ button_edge(now, KeyCross, PSXI_SW_SDA_CROSS);
+ button_edge(now, KeySquare, PSXI_SW_SDA_SQUARE);
+ button_edge(now, KeyTriangle, PSXI_SW_SDA_TRIANGLE);
+ button_edge(now, KeyCircle, PSXI_SW_SDA_CIRCLE);
+ button_edge(now, KeyStart, PSXI_SW_SDA_START);
+ button_edge(now, KeySelect, PSXI_SW_SDA_SELECT);
+ button_edge(now, KeyUp, PSXI_SW_SDA_PAD_UP);
+ button_edge(now, KeyDown, PSXI_SW_SDA_PAD_DOWN);
+ button_edge(now, KeyLeft, PSXI_SW_SDA_PAD_LEFT);
+ button_edge(now, KeyRight, PSXI_SW_SDA_PAD_RIGHT);
+ button_edge(now, KeyL1, PSXI_SW_SDA_L1);
+ button_edge(now, KeyR1, PSXI_SW_SDA_R1);
+ button_edge(now, KeyL2, PSXI_SW_SDA_L2);
+ button_edge(now, KeyR2, PSXI_SW_SDA_R2);
+ button_edge(now, KeyL3, PSXI_SW_SDA_L3);
+ button_edge(now, KeyR3, PSXI_SW_SDA_R3);
+ button_edge(now, KeyAnalog, PSXI_SW_SDA_ANALOG);
+
+ emu.prevkeys = now;
+}
+
+void
+bindkeys(void)
+{+ regkey("cross", 'x', KeyCross);+ regkey("square", 'z', KeySquare);+ regkey("triangle", 's', KeyTriangle);+ regkey("circle", 'd', KeyCircle);+ regkey("start", '\n', KeyStart);+ regkey("select", Kshift, KeySelect);+ regkey("up", Kup, KeyUp);+ regkey("down", Kdown, KeyDown);+ regkey("left", Kleft, KeyLeft);+ regkey("right", Kright, KeyRight);+ regkey("l1", 'q', KeyL1);+ regkey("r1", 'w', KeyR1);+ regkey("l2", '1', KeyL2);+ regkey("r2", '3', KeyR2);+ regkey("l3", 'a', KeyL3);+ regkey("r3", 'f', KeyR3);+ regkey("analog", '2', KeyAnalog);+}
+
+void
+blitframe(void)
+{+ u32int *dst, *drow;
+ u16int *s16, *row16;
+ uchar *s8, *row8;
+ void *src;
+ int fmt, sw, sh, dx, dy, x, y;
+
+ if(emu.psx == nil)
+ return;
+
+ src = psx_get_display_buffer(emu.psx);
+ fmt = psx_get_display_format(emu.psx);
+ sw = psx_get_display_width(emu.psx);
+ sh = psx_get_display_height(emu.psx);
+
+ if(emu.psx->gpu->disp_y + sh > PSX_GPU_FB_HEIGHT)
+ src = psx_get_vram(emu.psx);
+
+ if(sw <= 0 || sh <= 0)
+ return;
+
+ if(sw > Vwdx)
+ sw = Vwdx;
+ if(sh > Vwdy)
+ sh = Vwdy;
+
+ dx = (Vwdx - sw) / 2;
+ dy = (Vwdy - sh) / 2;
+
+ memset(pic, 0, Vwdx * Vwdy * 4);
+
+ dst = (u32int*)pic;
+
+ if(fmt != 0){+ s8 = (uchar*)src;
+ for(y = 0; y < sh; y++){+ row8 = s8 + (y * PSX_GPU_FB_STRIDE);
+ drow = dst + ((dy + y) * Vwdx) + dx;
+ for(x = 0; x < sw; x++){+ u32int b, g, r;
+
+ b = row8[(x * 3) + 0];
+ g = row8[(x * 3) + 1];
+ r = row8[(x * 3) + 2];
+
+ drow[x] = 0xff000000 | (r << 16) | (g << 8) | b;
+ }
+ }
+ return;
+ }
+
+ s16 = (u16int*)src;
+ for(y = 0; y < sh; y++){+ row16 = s16 + (y * PSX_GPU_FB_WIDTH);
+ drow = dst + ((dy + y) * Vwdx) + dx;
+ for(x = 0; x < sw; x++)
+ drow[x] = bgr555toxrgb32(row16[x]);
+ }
+}
+
+int
+audioout(void)
+{+ return -1;
+}
+
+void
+flush(void)
+{+ flushmouse(1);
+ flushscreen();
+ flushaudio(audioout);
+}
+
+void
+psxe_gpu_vblank_event_cb(psx_gpu_t *gpu)
+{+ blitframe();
+ flush();
+ psxe_gpu_vblank_timer_event_cb(gpu);
+}
+
+void
+usage(void)
+{+ fprint(2, "usage: %s [-x scale] [-e expansion] bios [disc]\n", argv0);
+ exits("usage");+}
+
+void
+threadmain(int argc, char **argv)
+{+ char *bios, *disc, *exp;
+ psx_input_t *input;
+ psxi_sda_t *controller;
+ psx_gpu_t *gpu;
+ int r;
+
+ log_set_quiet(0);
+ log_set_level(LOG_WARN);
+
+ disc = nil;
+ exp = nil;
+
+ ARGBEGIN{+ case 'x':
+ fixscale = strtol(EARGF(usage()), nil, 0);
+ break;
+ case 'e':
+ exp = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc < 1 || argc > 2)
+ usage();
+
+ bios = argv[0];
+ if(argc == 2)
+ disc = argv[1];
+
+ memset(&emu, 0, sizeof emu);
+
+ emu.psx = psx_create();
+ if(emu.psx == nil)
+ sysfatal("psx_create: %r");+
+ r = psx_init(emu.psx, bios, exp);
+ if(r != 0)
+ sysfatal("psx_init failed: %d", r);+
+ emu.pad = psx_get_pad(emu.psx);
+
+ if(disc != nil && !psx_cdrom_open(psx_get_cdrom(emu.psx), disc))
+ fprint(2, "warning: cannot open disc %s\n", disc);
+
+ input = psx_input_create();
+ psx_input_init(input);
+
+ controller = psxi_sda_create();
+ psxi_sda_init(controller, SDA_MODEL_DIGITAL);
+ psxi_sda_init_input(controller, input);
+
+ psx_pad_attach_joy(emu.pad, 0, input);
+ psx_pad_attach_mcd(emu.pad, 0, "slot1.mcd");
+ psx_pad_attach_mcd(emu.pad, 1, "slot2.mcd");
+
+ gpu = psx_get_gpu(emu.psx);
+
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK, psxe_gpu_vblank_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK, psxe_gpu_hblank_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK_END, psxe_gpu_vblank_end_event_cb);
+ psx_gpu_set_event_callback(gpu, GPU_EVENT_HBLANK_END, psxe_gpu_hblank_end_event_cb);
+
+ psx_gpu_set_udata(gpu, 1, psx_get_timer(emu.psx));
+
+ initemu(Vwdx, Vwdy, 4, XRGB32, 1, nil);
+ bindkeys();
+
+ for(;;){+ if(paused){+ qlock(&pauselock);
+ qunlock(&pauselock);
+ }
+ process_inputs();
+ psx_update(emu.psx);
+ }
+}
--
⑨