#include "compiler.h"
#if defined(SUPPORT_ROMEO)
#include "romeo.h"
#include "juliet.h"
enum {
ROMEO_AVAIL = 0x01,
ROMEO_YMF288 = 0x02,
ROMEO_YM2151 = 0x04
};
typedef struct {
HMODULE mod;
ULONG (WINAPI * finddev)(ULONG ven, ULONG dev, ULONG index);
ULONG (WINAPI * read32)(ULONG pciaddr, ULONG regaddr);
void (WINAPI * out8)(ULONG addr, UCHAR param);
void (WINAPI * out16)(ULONG addr, USHORT param);
void (WINAPI * out32)(ULONG addr, ULONG param);
UCHAR (WINAPI * in8)(ULONG addr);
USHORT (WINAPI * in16)(ULONG addr);
ULONG (WINAPI * in32)(ULONG addr);
ULONG addr;
ULONG irq;
ULONG avail;
UINT8 algo[8];
UINT8 ttl[8*4];
UINT8 psgmix;
} _ROMEO;
static const UINT8 opmask[] = {0x08,0x08,0x08,0x08,0x0c,0x0e,0x0e,0x0f};
typedef struct {
const char *symbol;
UINT addr;
} DLLPROC;
static const DLLPROC dllproc[] = {
{FN_PCIFINDDEV, offsetof(_ROMEO, finddev)},
{FN_PCICFGREAD32, offsetof(_ROMEO, read32)},
{FN_PCIMEMWR8, offsetof(_ROMEO, out8)},
{FN_PCIMEMWR16, offsetof(_ROMEO, out16)},
{FN_PCIMEMWR32, offsetof(_ROMEO, out32)},
{FN_PCIMEMRD8, offsetof(_ROMEO, in8)},
{FN_PCIMEMRD16, offsetof(_ROMEO, in16)},
{FN_PCIMEMRD32, offsetof(_ROMEO, in32)}};
static _ROMEO romeo = {NULL};
// pciFindPciDevice使うと、OS起動後一発目に見つけられないことが多いので、
// 自前で検索する(矢野さん方式)
#define PCIBUSDEVFUNC(b, d, f) (((b) << 8) | ((d) << 3) | (f))
#define DEVVEND(v, d) ((ULONG)((v) | ((d) << 16)))
static ULONG searchRomeo(void) {
UINT bus;
UINT dev;
UINT func;
ULONG addr;
ULONG dev_vend;
for (bus=0; bus<0x100; bus++) {
for (dev=0; dev<0x20; dev++) {
for (func=0; func<0x08; func++) {
addr = PCIBUSDEVFUNC(bus, dev, func);
dev_vend = romeo.read32(addr, 0x0000);
if ((dev_vend == DEVVEND(ROMEO_VENDORID, ROMEO_DEVICEID)) ||
(dev_vend == DEVVEND(ROMEO_VENDORID, ROMEO_DEVICEID2))) {
return(addr);
}
}
}
}
return((ULONG)0xffffffff);
}
BOOL juliet_initialize(void) {
HMODULE mod;
const DLLPROC *d;
const DLLPROC *dterm;
long proc;
ULONG pciaddr;
juliet_deinitialize();
mod = LoadLibrary(PCIDEBUG_DLL);
if (mod == NULL) {
goto jini_err1;
}
romeo.mod = mod;
d = dllproc;
dterm = d + sizeof(dllproc)/sizeof(DLLPROC);
while(d < dterm) {
proc = (long)GetProcAddress(mod, d->symbol);
if (proc == (long)NULL) {
MessageBox(NULL, "0", "?", MB_OK);
goto jini_err2;
}
*(long *)(((BYTE *)&romeo) + (d->addr)) = proc;
d++;
}
pciaddr = searchRomeo();
if (pciaddr == (ULONG)0xffffffff) {
goto jini_err2;
}
romeo.addr = romeo.read32(pciaddr, ROMEO_BASEADDRESS1);
romeo.irq = romeo.read32(pciaddr, ROMEO_PCIINTERRUPT) & 0xff;
if (!romeo.addr) {
goto jini_err2;
}
romeo.avail = ROMEO_AVAIL | ROMEO_YMF288;
juliet_YMF288Reset();
TRACEOUT(("ROMEO enable"));
return(SUCCESS);
jini_err2:
juliet_deinitialize();
jini_err1:
return(FAILURE);
}
void juliet_deinitialize(void) {
if (romeo.mod) {
FreeLibrary(romeo.mod);
}
ZeroMemory(&romeo, sizeof(romeo));
FillMemory(romeo.ttl, 8*4, 0x7f);
romeo.psgmix = 0x3f;
}
// ---- YMF288部
static void YMF288A(UINT8 addr, UINT8 data) {
while(romeo.in8(romeo.addr + ROMEO_YMF288ADDR1) & 0x80) {
Sleep(0);
}
romeo.out8(romeo.addr + ROMEO_YMF288ADDR1, addr);
while(romeo.in8(romeo.addr + ROMEO_YMF288ADDR1) & 0x80) {
Sleep(0);
}
romeo.out8(romeo.addr + ROMEO_YMF288DATA1, data);
}
static void YMF288B(UINT8 addr, UINT8 data) {
while(romeo.in8(romeo.addr + ROMEO_YMF288ADDR1) & 0x80) {
Sleep(0);
}
romeo.out8(romeo.addr + ROMEO_YMF288ADDR2, addr);
while(romeo.in8(romeo.addr + ROMEO_YMF288ADDR1) & 0x80) {
Sleep(0);
}
romeo.out8(romeo.addr + ROMEO_YMF288DATA2, data);
}
static void setvolume(UINT8 ch, int vol) {
void (*send)(UINT8 addr, UINT8 data);
UINT8 mask;
UINT8 *pttl;
int ttl;
send = (ch & 4)?YMF288B:YMF288A;
mask = opmask[romeo.algo[ch & 7] & 7];
pttl = romeo.ttl + ((ch & 4) << 2);
ch = 0x40 + (ch & 3);
do {
if (mask & 1) {
ttl = pttl[ch & 0x0f] & 0x7f;
ttl -= vol;
if (ttl < 0) {
ttl = 0;
}
else if (ttl > 0x7f) {
ttl = 0x7f;
}
send(ch, (UINT8)ttl);
}
ch += 4;
mask >>= 1;
} while(mask);
}
void juliet_YMF288Reset(void) {
if (romeo.avail & ROMEO_YMF288) {
romeo.out32(romeo.addr + ROMEO_YMF288CTRL, 0x00);
Sleep(150);
romeo.out32(romeo.addr + ROMEO_YMF288CTRL, 0x80);
Sleep(150);
}
}
BOOL juliet_YMF288IsEnable(void) {
return((romeo.avail & ROMEO_YMF288) != 0);
}
BOOL juliet_YMF288IsBusy(void) {
return((!(romeo.avail & ROMEO_YMF288)) ||
((romeo.in8(romeo.addr + ROMEO_YMF288ADDR1) & 0x80) != 0));
}
void juliet_YMF288A(UINT8 addr, UINT8 data) {
if (romeo.avail & ROMEO_YMF288) {
if (addr == 0x07) { // psg mix
romeo.psgmix = data;
}
else if ((addr & 0xf0) == 0x40) { // ttl
romeo.ttl[addr & 0x0f] = data;
}
else if ((addr & 0xfc) == 0xb0) { // algorithm
romeo.algo[addr & 3] = data;
}
YMF288A(addr, data);
}
}
void juliet_YMF288B(UINT8 addr, UINT8 data) {
if (romeo.avail & ROMEO_YMF288) {
if ((addr & 0xf0) == 0x40) { // ttl
romeo.ttl[0x10 + (addr & 0x0f)] = data;
}
else if ((addr & 0xfc) == 0xb0) { // algorithm
romeo.algo[4 + (addr & 3)] = data;
}
YMF288B(addr, data);
}
}
void juliet_YMF288Enable(BOOL enable) {
UINT8 ch;
int vol;
if (romeo.avail & ROMEO_YMF288) {
YMF288A(0x07, (enable)?romeo.psgmix:0x3f);
vol = (enable)?0:-127;
for (ch=0; ch<3; ch++) {
setvolume(ch+0, vol);
setvolume(ch+4, vol);
}
}
}
#endif
RetroPC.NET-CVS <cvs@retropc.net>