add driver and soundcore for Rabbit - yes the sound really is that bad. not a bug

This commit is contained in:
dinkc64 2020-02-22 01:28:14 -05:00
parent 04b3caec2b
commit 40db6a7742
4 changed files with 1216 additions and 2 deletions

View File

@ -74,7 +74,7 @@ drvsrc = d_akkaarrh.o d_arcadecl.o d_atarig1.o d_badlands.o d_batman.o d_blstro
d_esd16.o d_f1gp.o d_funybubl.o d_fuukifg2.o d_fuukifg3.o d_gaelco.o d_gaelco2.o d_gaiden.o d_galpanic.o d_galspnbl.o d_glass.o d_go2000.o \
d_gotcha.o d_gumbo.o d_hyperpac.o d_itech32.o d_jchan.o d_kaneko16.o d_legionna.o d_lordgun.o d_macrossp.o d_mcatadv.o d_metro.o d_midas.o d_mirage.o d_missb2.o d_mosaic.o \
d_mugsmash.o d_mwarr.o d_namcos2.o d_news.o d_nmg5.o d_nmk16.o d_ohmygod.o d_oneshot.o d_onetwo.o d_pass.o d_patapata.o \
d_pipedrm.o d_pirates.o d_pkscram.o d_playmark.o d_powerins.o d_ppmast93.o d_pushman.o d_raiden.o d_raiden2.o d_sandscrp.o d_seta.o d_seta2.o \
d_pipedrm.o d_pirates.o d_pkscram.o d_playmark.o d_powerins.o d_ppmast93.o d_pushman.o d_rabbit.o d_raiden.o d_raiden2.o d_sandscrp.o d_seta.o d_seta2.o \
d_shadfrce.o d_silkroad.o d_silvmil.o d_speedspn.o d_ssv.o d_suna16.o d_supduck.o d_suprnova.o d_taotaido.o d_targeth.o d_tecmo16.o d_tecmosys.o \
d_tetrisp2.o d_thoop2.o d_tumbleb.o d_unico.o d_vmetal.o d_welltris.o d_wrally.o d_wwfwfest.o d_xorworld.o d_yunsun16.o d_yunsung8.o d_zerozone.o \
\
@ -103,7 +103,7 @@ depobj = burn.o burn_bitmap.o burn_gun.o burn_led.o burn_shift.o burn_memory.o
\
asteroids.o ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o burn_md2612.o \
burn_ym3526.o burn_ym3812.o burn_ymf262.o burn_ymf278b.o bzone.o c6280.o dac.o es5506.o es8712.o flower.o flt_rc.o fm.o fmopl.o ym2612.o gaelco.o hc55516.o \
ics2115.o iremga20.o k005289.o k007232.o k051649.o k053260.o k054539.o llander.o msm5205.o msm5232.o msm6295.o namco_snd.o c140.o nes_apu.o \
i5000.o ics2115.o iremga20.o k005289.o k007232.o k051649.o k053260.o k054539.o llander.o msm5205.o msm5232.o msm6295.o namco_snd.o c140.o nes_apu.o \
tms5110.o tms5220.o tms36xx.o phoenixsound.o pleiadssound.o pokey.o redbaron.o rf5c68.o s14001a.o saa1099.o samples.o segapcm.o sn76477.o sn76496.o \
upd7759.o vlm5030.o wiping.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf262.o ymf278b.o ymz280b.o snk6502_sound.o sp0250.o sp0256.o \
\

View File

@ -0,0 +1,819 @@
// FinalBurn Neo Electronic Arts Rabbit driver module
// Based on MAME driver by David Haywood
// to do:
// sound - add volume adjust, etc
// notes:
// graphics banking for the main cpu is only used to test the rom checksums
// -this adds complexity and is not worth the time investment
// -banking in first 512k of graphics0 to keep the logger happy on reads
//
// possible mame over-flow bugs
// - blitter tilemap select can select 7, only has 4 tilemaps
// - blitter column select can be 0xff, later masks to 0x7f
// - sprite start offset can be 0xfff*2 for sprites (32-bit), this is 1ffe*4 (0x7ff8) ram is only 0x4000
#include "tiles_generic.h"
#include "m68000_intf.h"
#include "i5000.h"
#include "eeprom.h"
static UINT8 *AllMem;
static UINT8 *AllRam;
static UINT8 *RamEnd;
static UINT8 *MemEnd;
static UINT8 *Drv68KROM;
static UINT8 *DrvGfxROM[10];
static UINT8 *DrvSndROM;
static UINT8 *DrvEEPROM;
static UINT8 *Drv68KRAM;
static UINT8 *DrvPalRAM;
static UINT8 *DrvVidRAM[4];
static UINT8 *DrvSprRAM;
static UINT32 *DrvPalette;
static UINT8 DrvRecalc;
static UINT32 *tilemapregs[4];
static UINT32 *spriteregs;
static UINT32 *blitterregs;
static INT32 blitter_irq;
static INT32 update_tilemap[4];
static UINT8 DrvJoy1[32];
static UINT32 DrvInputs[1];
static UINT8 DrvReset;
static struct BurnInputInfo RabbitInputList[] = {
{"P1 Coin", BIT_DIGITAL, DrvJoy1 + 6, "p1 coin" },
{"P1 Start", BIT_DIGITAL, DrvJoy1 + 2, "p1 start" },
{"P1 Up", BIT_DIGITAL, DrvJoy1 + 8, "p1 up" },
{"P1 Down", BIT_DIGITAL, DrvJoy1 + 9, "p1 down" },
{"P1 Left", BIT_DIGITAL, DrvJoy1 + 10, "p1 left" },
{"P1 Right", BIT_DIGITAL, DrvJoy1 + 11, "p1 right" },
{"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 12, "p1 fire 1" },
{"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 13, "p1 fire 2" },
{"P1 Button 3", BIT_DIGITAL, DrvJoy1 + 14, "p1 fire 3" },
{"P1 Button 4", BIT_DIGITAL, DrvJoy1 + 15, "p1 fire 4" },
{"P2 Coin", BIT_DIGITAL, DrvJoy1 + 7, "p2 coin" },
{"P2 Start", BIT_DIGITAL, DrvJoy1 + 3, "p2 start" },
{"P2 Up", BIT_DIGITAL, DrvJoy1 + 16, "p2 up" },
{"P2 Down", BIT_DIGITAL, DrvJoy1 + 17, "p2 down" },
{"P2 Left", BIT_DIGITAL, DrvJoy1 + 18, "p2 left" },
{"P2 Right", BIT_DIGITAL, DrvJoy1 + 19, "p2 right" },
{"P2 Button 1", BIT_DIGITAL, DrvJoy1 + 20, "p2 fire 1" },
{"P2 Button 2", BIT_DIGITAL, DrvJoy1 + 21, "p2 fire 2" },
{"P2 Button 3", BIT_DIGITAL, DrvJoy1 + 22, "p2 fire 3" },
{"P2 Button 4", BIT_DIGITAL, DrvJoy1 + 23, "p2 fire 4" },
{"Reset", BIT_DIGITAL, &DrvReset, "reset" },
{"Service", BIT_DIGITAL, DrvJoy1 + 4, "service" },
{"Service Mode", BIT_DIGITAL, DrvJoy1 + 5, "diag" },
};
STDINPUTINFO(Rabbit)
static void blitter_write()
{
UINT32 reg0 = (blitterregs[0]<<16)|(blitterregs[0]>>16);
UINT32 reg1 = (blitterregs[1]<<16)|(blitterregs[1]>>16);
UINT32 reg2 = (blitterregs[2]<<16)|(blitterregs[2]>>16);
INT32 blt_source = (reg0&0x000fffff) >> 0;
INT32 blt_column = (reg1&0x00ff0000) >> 16; // should this be 0x7f?
INT32 blt_line = (reg1&0x000000ff) >> 0;
INT32 blt_tilemp = (reg2&0x00006000) >> 13; // MAME has e...
INT32 blt_oddflg = (reg2&0x00000001) >> 0;
INT32 mask,shift;
UINT32 *tilemap_ram[4] = { (UINT32*)DrvVidRAM[0], (UINT32*)DrvVidRAM[1], (UINT32*)DrvVidRAM[2], (UINT32*)DrvVidRAM[3] };
if (!blt_oddflg) // inverted vs MAME
{
mask = 0xffff0000;
shift= 0;
}
else
{
mask = 0x0000ffff;
shift= 16;
}
blt_oddflg = 0x80 * blt_line;
blt_source <<= 1;
while (1)
{
INT32 blt_amount = DrvGfxROM[0][blt_source++];
INT32 blt_commnd = DrvGfxROM[0][blt_source++];
switch (blt_commnd)
{
case 0x00: // copy nn bytes
{
if (!blt_amount)
{
blitter_irq = 1; // irq line 4 after 500us
return;
}
for (INT32 loopcount = 0; loopcount < blt_amount; loopcount++)
{
INT32 blt_value = ((DrvGfxROM[0][blt_source^1]<<8)|(DrvGfxROM[0][blt_source^0]));
blt_source+=2;
INT32 writeoffs=blt_oddflg+blt_column;
tilemap_ram[blt_tilemp][writeoffs]=(tilemap_ram[blt_tilemp][writeoffs]&mask)|(blt_value<<shift);
GenericTilemapSetTileDirty(blt_tilemp, writeoffs);
update_tilemap[blt_tilemp] = 1;
blt_column++;
blt_column&=0x7f;
}
}
break;
case 0x02: // fill nn bytes
{
INT32 blt_value = ((DrvGfxROM[0][blt_source^1]<<8)|(DrvGfxROM[0][blt_source^0]));
blt_source+=2;
for (INT32 loopcount = 0; loopcount < blt_amount; loopcount++)
{
INT32 writeoffs=blt_oddflg+blt_column;
tilemap_ram[blt_tilemp][writeoffs]=(tilemap_ram[blt_tilemp][writeoffs]&mask)|(blt_value<<shift);
GenericTilemapSetTileDirty(blt_tilemp, writeoffs);
update_tilemap[blt_tilemp] = 1;
blt_column++;
blt_column&=0x7f;
}
}
break;
case 0x03: // next line
blt_column = (reg1&0x00ff0000)>>16;
blt_oddflg+=128;
break;
default:
bprintf (0, _T("BLIT ERROR! %x. %x\n"), blt_commnd, blt_amount);
}
}
}
static void __fastcall rabbit_write_long(UINT32 address, UINT32 data)
{
data = (data << 16) | (data >> 16);
if ((address & 0xffffe0) == 0x400200) {
spriteregs[(address / 4) & 7] = data;
return;
}
if ((address & 0xfffff0) == 0x400700) {
blitterregs[(address / 4) & 3] = data;
return;
}
// bprintf (0, _T("WL: %5.5x, %8.8x\n"), address, data);
}
static void __fastcall rabbit_write_word(UINT32 address, UINT16 data)
{
if ((address & 0xffff80) == 0x400100) {
UINT16 *regs = (UINT16*)tilemapregs[(address / 0x20) & 3];
regs[(address / 2) & 0xf] = data;
return;
}
if ((address & 0xffffe0) == 0x400200) {
UINT16 *regs = (UINT16*)spriteregs;
regs[(address / 2) & 0xf] = data;
return;
}
if ((address & 0xfffffc) == 0x400300) {
// rombank_w
return;
}
if (address == 0x40070e) {
blitter_write();
return;
}
if ((address & 0xffff00) == 0x400900) {
i5000sndWrite((address / 2) & 0x7f, data);
return;
}
// bprintf (0, _T("WW: %5.5x, %2.2x\n"), address, data);
}
static void __fastcall rabbit_write_byte(UINT32 address, UINT8 data)
{
if (address == 0x200000) {
EEPROMWriteBit((data & 0x01));
EEPROMSetCSLine((~data & 0x04) ? EEPROM_ASSERT_LINE : EEPROM_CLEAR_LINE);
EEPROMSetClockLine((data & 0x02) ? EEPROM_ASSERT_LINE : EEPROM_CLEAR_LINE);
return;
}
// bprintf (0, _T("WB: %5.5x, %2.2x\n"), address, data);
}
static UINT32 __fastcall rabbit_read_long(UINT32 address)
{
if (address == 0x200000) return DrvInputs[0] | (EEPROMRead() ? 1 : 0);
// bprintf (0, _T("RL: %5.5x\n"), address & 0xff);
return 0;
}
static UINT16 __fastcall rabbit_read_word(UINT32 address)
{
if (address == 0x400012) return BurnRandom();
if ((address & 0xffff00) == 0x400900) return i5000sndRead((address / 2) & 0x7f);
// bprintf (0, _T("RW: %8.8x\n"), address);
return 0;
}
static UINT8 __fastcall rabbit_read_byte(UINT32 address)
{
if (address == 0x200003) return (DrvInputs[0] & 0xfe) | (EEPROMRead() ? 1 : 0); // only this one ever read?
// bprintf (0, _T("RB: %5.5x\n"), address);
return 0;
}
static void __fastcall rabbit_videoram_write_long(UINT32 address, UINT32 data)
{
data = (data << 16) | (data >> 16);
INT32 offset = (address & 0x3ffc) / 4;
INT32 select = (address / 0x4000) & 3;
UINT32 *ram = (UINT32*)(DrvVidRAM[select]);
if (ram[offset] != data) {
GenericTilemapSetTileDirty(select, offset);
update_tilemap[select] = 1;
ram[offset] = data;
}
}
static void __fastcall rabbit_videoram_write_word(UINT32 address, UINT16 data)
{
INT32 offset = (address & 0x3ffe) / 2;
INT32 select = (address / 0x4000) & 3;
UINT16 *ram = (UINT16*)(DrvVidRAM[select]);
if (ram[offset] != data) {
GenericTilemapSetTileDirty(select, offset/2);
update_tilemap[select] = 1;
ram[offset] = data;
}
}
static void __fastcall rabbit_videoram_write_byte(UINT32 address, UINT8 data)
{
INT32 offset = (address & 0x3fff) ^ 1;
INT32 select = (address / 0x4000) & 3;
UINT8 *ram = (UINT8*)(DrvVidRAM[select]);
if (ram[offset] != data) {
GenericTilemapSetTileDirty(select, offset/4);
update_tilemap[select] = 1;
ram[offset] = data;
}
}
static inline void palette_write(UINT16 i)
{
DrvPalette[i/4] = BurnHighCol(DrvPalRAM[i+3],DrvPalRAM[i+0],DrvPalRAM[i+2],0);
}
static void __fastcall rabbit_paletteram_write_long(UINT32 address, UINT32 data)
{
UINT32 *ram = (UINT32*)DrvPalRAM;
ram[(address & 0xfffc)/4] = (data << 16) | (data >> 16);
palette_write(address & 0xfffc);
}
static void __fastcall rabbit_paletteram_write_word(UINT32 address, UINT16 data)
{
UINT16 *ram = (UINT16*)DrvPalRAM;
ram[(address & 0xfffe)/2] = data;
palette_write(address & 0xfffc);
}
static void __fastcall rabbit_paletteram_write_byte(UINT32 address, UINT8 data)
{
UINT8 *ram = (UINT8*)DrvPalRAM;
ram[(address & 0xffff) ^ 1] = data;
palette_write(address & 0xfffc);
}
#define get_tilemap_info(which, size) \
UINT32 attr = *((UINT32*)(DrvVidRAM[which] + (offs * 4))); \
INT32 depth = (attr & 0x00001000) >> 12; \
INT32 code = (attr & 0xffff0000) >> 16; \
INT32 bank = (attr & 0x0000000f) >> 0; \
INT32 color = (attr & 0x00000ff0) >> 4; \
INT32 cmask = (attr & 0x00008000) >> 15; \
INT32 flip = (attr & 0x00006000) >> 13; \
\
if (bank == 8) code += 0x10000; \
if (bank == 12) code += 0x20000; \
\
if (depth) { \
code >>= ((size*2) + 1); \
} else { \
code >>= size * 2; \
if (cmask) color &= 0x3f; \
} \
TILE_SET_INFO((depth * 2) + size, code, color, TILE_FLIPXY(flip))
static tilemap_callback( layer0 )
{
get_tilemap_info(0,1);
}
static tilemap_callback( layer1 )
{
get_tilemap_info(1,1);
}
static tilemap_callback( layer2 )
{
get_tilemap_info(2,1);
}
static tilemap_callback( layer3 )
{
get_tilemap_info(3,0);
}
static INT32 DrvDoReset()
{
SekOpen(0);
SekReset();
SekClose();
i5000sndReset();
BurnRandomSetSeed(0xb00b1e5);
EEPROMReset();
if (EEPROMAvailable() == 0) {
EEPROMFill(DrvEEPROM, 0, 0x80);
}
blitter_irq = 0;
for (INT32 i = 0; i < 4; i++) {
GenericTilemapAllTilesDirty(i);
update_tilemap[i] = 1;
}
return 0;
}
static INT32 MemIndex()
{
UINT8 *Next; Next = AllMem;
Drv68KROM = Next; Next += 0x0200000;
DrvGfxROM[0] = Next; Next += 0x0200000; // blitter data
DrvGfxROM[1] = Next; Next += 0x0600000; // 8x8x8 / 8x16x16 tiles
DrvGfxROM[2] = Next; Next += 0x2000000; // 4x16x16 sprites
DrvGfxROM[3] = Next; Next += 0x0c00000; // 4x8x8 / 4x16x16 tiles
DrvSndROM = Next; Next += 0x0400018; // sound data + 24 byte header
DrvEEPROM = Next; Next += 0x0000080;
DrvPalette = (UINT32*)Next; Next += 0x04001 * sizeof(UINT32);
AllRam = Next;
Drv68KRAM = Next; Next += 0x0100000;
DrvPalRAM = Next; Next += 0x0100000;
DrvVidRAM[0] = Next; Next += 0x0200000; // only first 4000 accessible by cpu
DrvVidRAM[1] = Next; Next += 0x0200000; // ""
DrvVidRAM[2] = Next; Next += 0x0200000; // ""
DrvVidRAM[3] = Next; Next += 0x0200000; // ""
DrvSprRAM = Next; Next += 0x0040000;
tilemapregs[0] = (UINT32*)Next; Next += 0x000008 * sizeof(UINT32);
tilemapregs[1] = (UINT32*)Next; Next += 0x000008 * sizeof(UINT32);
tilemapregs[2] = (UINT32*)Next; Next += 0x000008 * sizeof(UINT32);
tilemapregs[3] = (UINT32*)Next; Next += 0x000008 * sizeof(UINT32);
blitterregs = (UINT32*)Next; Next += 0x000004 * sizeof(UINT32);
spriteregs = (UINT32*)Next; Next += 0x000008 * sizeof(UINT32);
RamEnd = Next;
MemEnd = Next;
return 0;
}
static INT32 DrvInit()
{
BurnAllocMemIndex();
{
INT32 k = 0;
if (BurnLoadRom(Drv68KROM + 0x000001, k++, 4)) return 1;
if (BurnLoadRom(Drv68KROM + 0x000000, k++, 4)) return 1;
if (BurnLoadRom(Drv68KROM + 0x000003, k++, 4)) return 1;
if (BurnLoadRom(Drv68KROM + 0x000002, k++, 4)) return 1;
if (BurnLoadRomExt(DrvGfxROM[2] + 0x000000, k++, 8, LD_GROUP(2))) return 1;
if (BurnLoadRomExt(DrvGfxROM[2] + 0x000002, k++, 8, LD_GROUP(2))) return 1;
if (BurnLoadRomExt(DrvGfxROM[2] + 0x000004, k++, 8, LD_GROUP(2))) return 1;
if (BurnLoadRomExt(DrvGfxROM[2] + 0x000006, k++, 8, LD_GROUP(2))) return 1;
if (BurnLoadRom(DrvGfxROM[1] + 0x000000, k++, 1)) return 1;
if (BurnLoadRom(DrvGfxROM[1] + 0x200000, k++, 1)) return 1;
if (BurnLoadRom(DrvGfxROM[1] + 0x400000, k++, 1)) return 1;
if (BurnLoadRom(DrvSndROM + 0x000000, k++, 1)) return 1;
DrvSndROM += 0x18; // skip header
if (BurnLoadRom(DrvEEPROM + 0x000000, k++, 1)) return 1;
for (INT32 i = 0; i < 0x200000; i++) { // copy blitter data out of sprite graphics
DrvGfxROM[0][i] = DrvGfxROM[2][((i & 3) ^ 2) | ((i & 0x1ffffc) << 1)];
}
// expand into 4bpp tiles
BurnNibbleExpand(DrvGfxROM[1], DrvGfxROM[3], 0x0600000, 1, 0);
BurnNibbleExpand(DrvGfxROM[2], DrvGfxROM[2], 0x1000000, 1, 0);
}
SekInit(0, 0x68ec020);
SekOpen(0);
SekMapMemory(Drv68KROM, 0x000000, 0x1fffff, MAP_ROM);
SekMapMemory(DrvGfxROM[0], 0x440000, 0x47ffff, MAP_ROM); // bank graphics (don't bother)
SekMapMemory(DrvVidRAM[0], 0x480000, 0x483fff, MAP_RAM);
SekMapMemory(DrvVidRAM[1], 0x484000, 0x487fff, MAP_RAM);
SekMapMemory(DrvVidRAM[2], 0x488000, 0x48bfff, MAP_RAM);
SekMapMemory(DrvVidRAM[3], 0x48c000, 0x48ffff, MAP_ROM);
SekMapMemory(DrvSprRAM, 0x494000, 0x497fff, MAP_RAM);
SekMapMemory(DrvPalRAM, 0x4a0000, 0x4affff, MAP_RAM);
SekMapMemory(Drv68KRAM, 0xff0000, 0xffffff, MAP_RAM);
SekSetWriteLongHandler(0, rabbit_write_long);
SekSetWriteWordHandler(0, rabbit_write_word);
SekSetWriteByteHandler(0, rabbit_write_byte);
SekSetReadLongHandler(0, rabbit_read_long);
SekSetReadWordHandler(0, rabbit_read_word);
SekSetReadByteHandler(0, rabbit_read_byte);
SekMapHandler(1, 0x480000, 0x48ffff, MAP_WRITE);
SekSetWriteLongHandler(1, rabbit_videoram_write_long);
SekSetWriteWordHandler(1, rabbit_videoram_write_word);
SekSetWriteByteHandler(1, rabbit_videoram_write_byte);
SekMapHandler(2, 0x4a0000, 0x4affff, MAP_WRITE);
SekSetWriteLongHandler(2, rabbit_paletteram_write_long);
SekSetWriteWordHandler(2, rabbit_paletteram_write_word);
SekSetWriteByteHandler(2, rabbit_paletteram_write_byte);
SekClose();
EEPROMInit(&eeprom_interface_93C46);
i5000sndInit(DrvSndROM, 40000000, 0x400000);
GenericTilesInit();
GenericTilemapInit(0, TILEMAP_SCAN_ROWS, layer0_map_callback, 16, 16, 128, 32);
GenericTilemapInit(1, TILEMAP_SCAN_ROWS, layer1_map_callback, 16, 16, 128, 32);
GenericTilemapInit(2, TILEMAP_SCAN_ROWS, layer2_map_callback, 16, 16, 128, 32);
GenericTilemapInit(3, TILEMAP_SCAN_ROWS, layer3_map_callback, 8, 8, 128, 32);
GenericTilemapSetGfx(0, DrvGfxROM[3], 4, 8, 8, 0x0c00000, 0x2000, 0xff);
GenericTilemapSetGfx(1, DrvGfxROM[3], 4, 16, 16, 0x0c00000, 0x2000, 0xff);
GenericTilemapSetGfx(2, DrvGfxROM[1], 8, 8, 8, 0x0600000, 0x6000, 0x0f); // color offset | 0x4000 (masked in bitmap copy)
GenericTilemapSetGfx(3, DrvGfxROM[1], 8, 16, 16, 0x0600000, 0x6000, 0x0f); // color offset | 0x4000 (masked in bitmap copy)
GenericTilemapSetGfx(4, DrvGfxROM[2], 4, 16, 16, 0x2000000, 0x0000, 0xff); // sprites
GenericTilemapUseDirtyTiles(0);
GenericTilemapUseDirtyTiles(1);
GenericTilemapUseDirtyTiles(2);
GenericTilemapUseDirtyTiles(3);
BurnBitmapAllocate(1, 2048, 512, true);
BurnBitmapAllocate(2, 2048, 512, true);
BurnBitmapAllocate(3, 2048, 512, true);
BurnBitmapAllocate(4, 1024, 256, true);
BurnBitmapAllocate(5, 4096, 4096, true);
DrvDoReset();
return 0;
}
static INT32 DrvExit()
{
GenericTilesExit();
SekExit();
EEPROMExit();
i5000sndExit();
BurnFreeMemIndex();
return 0;
}
static void DrvPaletteUpdate()
{
for (INT32 i = 0; i < 0x10000; i+=4) {
DrvPalette[i/4] = BurnHighCol(DrvPalRAM[i+3],DrvPalRAM[i+0],DrvPalRAM[i+2],0);
}
DrvPalette[0x4000] = 0; // black
}
static void clearspritebitmap()
{
INT32 starty = (spriteregs[1]&0x00000fff) - 200;
INT32 startx =((spriteregs[0]&0x0fff0000)>>16) - 200;
INT32 amountx = 650;
INT32 amounty = 600;
if (startx < 0) { amountx += startx; startx = 0; }
if ((startx+amountx)>=0x1000) amountx-=(0x1000-(startx+amountx));
for (INT32 y=0; y<amounty;y++)
{
UINT16 *dstline = BurnBitmapGetPosition(5, 0, (starty+y) & 0xfff);
memset(dstline+startx,0x00,amountx*2);
}
}
static void draw_sprites()
{
UINT16 *ram = (UINT16*)DrvSprRAM;
for (INT32 offs = (((spriteregs[5] & 0x0fff) - 1) * 4); offs >= 0; offs -= 4)
{
INT32 sy = ram[offs + 0] & 0x0fff;
INT32 sx = ram[offs + 1] & 0x0fff;
INT32 flipx = ram[offs + 1] & 0x8000;
INT32 flipy = ram[offs + 1] & 0x4000;
INT32 color =(ram[offs + 2] >> 4) & 0xff;
INT32 code =(ram[offs + 3] | (ram[offs + 2] << 16)) & 0x1ffff;
if (sx & 0x800) sx-=0x1000;
DrawGfxMaskTile(5, 4, code, sx+0x20-8, sy-24, flipx, flipy, color, 0xf);
}
}
static void draw_sprite_bitmap()
{
INT32 startx = ((spriteregs[0]>>16)&0x00000fff) - (((spriteregs[1]>>16)&0x000001ff)>>1);
INT32 starty = ((spriteregs[1]&0x0fff)) - (((spriteregs[1]>>16)&0x000001ff)>>1);
UINT32 xsize = ((spriteregs[2]>>16)) + 0x80;
UINT32 ysize = ((spriteregs[3]>>16)) + 0x80;
UINT32 xstep = ((320*128)<<16) / xsize;
UINT32 ystep = ((224*128)<<16) / ysize;
for (UINT32 y=0;y<ysize;y+=0x80)
{
UINT32 ydrawpos = ((y>>7)*ystep) >> 16;
if (ydrawpos < (UINT32)nScreenHeight)
{
UINT16 *srcline = BurnBitmapGetPosition(5, 0, (starty+(y>>7))&0xfff);
UINT16 *dstline = BurnBitmapGetPosition(0, 0, ydrawpos);
for (UINT32 x=0;x<xsize;x+=0x80)
{
UINT32 xdrawpos = ((x>>7)*xstep) >> 16;
UINT16 pixdata = srcline[(startx+(x>>7))&0xfff];
if (pixdata)
if (xdrawpos < (UINT32)nScreenWidth)
dstline[xdrawpos] = pixdata;
}
}
}
}
static void drawtilemap(INT32 whichtilemap) // line zoom
{
if ((nBurnLayer & (1 << whichtilemap)) == 0) return;
UINT16 *dst = pTransDraw;
INT32 minx, maxx, miny, maxy;
BurnBitmapGetClipDims(whichtilemap + 1, &minx, &maxx, &miny, &maxy);
UINT16 *src = BurnBitmapGetBitmap(1 + whichtilemap);
INT32 width = maxx - minx;
INT32 height = maxy - miny;
INT32 wmask = width - 1;
INT32 hmask = height - 1;
INT32 starty=((tilemapregs[whichtilemap][1]&0x0000ffff)) << 12;
INT32 startx=((tilemapregs[whichtilemap][1]&0xffff0000)>>16) << 12;
INT32 incyy= ((tilemapregs[whichtilemap][4]&0x00000fff)) << 5;
INT32 incxx= ((tilemapregs[whichtilemap][3]&0x0fff0000)>>16) << 5;
if (update_tilemap[whichtilemap])
{
GenericTilemapDraw(whichtilemap, 1 + whichtilemap, 0);
update_tilemap[whichtilemap] = 0;
}
for (INT32 sy = 0; sy < nScreenHeight; sy++, starty+=incyy)
{
UINT32 cx = startx;
UINT16 *line = src + ((starty >> 16) & hmask) * width;
for (INT32 x = 0; x < nScreenWidth; x++, cx+=incxx, dst++)
{
INT32 pxl = line[(cx >> 16) & wmask];
if ((pxl & 0x40ff) != 0x40ff) {
if ((pxl & 0x400f) != 0x000f) {
*dst = pxl & 0x3fff;
}
}
}
}
}
static INT32 DrvDraw()
{
if (DrvRecalc) {
DrvPaletteUpdate();
DrvRecalc = 0;
}
BurnTransferClear(0x4000);
for (UINT32 prilevel = 0xf00; prilevel > 0; prilevel-=0x100)
{
if (prilevel == (tilemapregs[3][0] & 0x0f00)) drawtilemap(3);
if (prilevel == (tilemapregs[2][0] & 0x0f00)) drawtilemap(2);
if (prilevel == (tilemapregs[1][0] & 0x0f00)) drawtilemap(1);
if (prilevel == (tilemapregs[0][0] & 0x0f00)) drawtilemap(0);
if ((prilevel == 0x0900) && (nSpriteEnable & 1))
{
clearspritebitmap();
draw_sprites();
draw_sprite_bitmap();
}
}
BurnTransferCopy(DrvPalette);
return 0;
}
static INT32 DrvFrame()
{
if (DrvReset) {
DrvDoReset();
}
{
DrvInputs[0] = 0xfffffffe;
for (INT32 i = 0; i < 32; i++) {
DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
}
}
INT32 nInterleave = 32;
INT32 nCyclesTotal = (INT32)((INT64)24000000 * nBurnCPUSpeedAdjust / (0x0100 * 60));
SekOpen(0);
for (INT32 i = 0; i < nInterleave; i++)
{
SekRun(nCyclesTotal / nInterleave);
if (blitter_irq) { SekSetIRQLine(4, CPU_IRQSTATUS_AUTO); blitter_irq = 0; }
}
SekSetIRQLine(6, CPU_IRQSTATUS_AUTO);
SekClose();
if (pBurnSoundOut) {
i5000sndUpdate(pBurnSoundOut, nBurnSoundLen);
}
if (pBurnDraw) {
BurnDrvRedraw();
}
return 0;
}
static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
{
struct BurnArea ba;
if (pnMin != NULL) {
*pnMin = 0x029682;
}
if (nAction & ACB_MEMORY_RAM) {
memset(&ba, 0, sizeof(ba));
ba.Data = AllRam;
ba.nLen = RamEnd-AllRam;
ba.szName = "All Ram";
BurnAcb(&ba);
}
if (nAction & ACB_DRIVER_DATA) {
SekScan(nAction);
BurnRandomScan(nAction);
i5000sndScan(nAction, pnMin);
SCAN_VAR(blitter_irq);
}
return 0;
}
// Rabbit (Asia 3/6)
static struct BurnRomInfo rabbitRomDesc[] = {
{ "jpr0.0", 0x080000, 0x52bb18c0, 1 | BRF_PRG | BRF_ESS }, // 0 M68ec020 Code
{ "jpr1.1", 0x080000, 0x38299d0d, 1 | BRF_PRG | BRF_ESS }, // 1
{ "jpr2.2", 0x080000, 0xfa3fd91a, 1 | BRF_PRG | BRF_ESS }, // 2
{ "jpr3.3", 0x080000, 0xd22727ca, 1 | BRF_PRG | BRF_ESS }, // 3
{ "jfv0.00", 0x400000, 0xb2a4d3d3, 2 | BRF_GRA }, // 4 Sprites
{ "jfv1.01", 0x400000, 0x83f3926e, 2 | BRF_GRA }, // 5
{ "jfv2.02", 0x400000, 0xb264bfb5, 2 | BRF_GRA }, // 6
{ "jfv3.03", 0x400000, 0x3e1a9be2, 2 | BRF_GRA }, // 7
{ "jbg0.40", 0x200000, 0x89662944, 3 | BRF_GRA }, // 8 Background Tiles
{ "jbg1.50", 0x200000, 0x1fc7f6e0, 3 | BRF_GRA }, // 9
{ "jbg2.60", 0x200000, 0xaee265fc, 3 | BRF_GRA }, // 10
{ "jsn0.11", 0x400000, 0xe1f726e8, 4 | BRF_GRA }, // 11 i5000snd Samples
{ "rabbit.nv", 0x000080, 0x73d471ed, 5 | BRF_PRG | BRF_ESS }, // 12 Default EEPROM
};
STD_ROM_PICK(rabbit)
STD_ROM_FN(rabbit)
struct BurnDriver BurnDrvRabbit = {
"rabbit", NULL, NULL, NULL, "1997",
"Rabbit (Asia 3/6)\0", NULL, "Aorn / Electronic Arts", "Miscellaneous",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING, 2, HARDWARE_MISC_POST90S, GBF_VSFIGHT, 0,
NULL, rabbitRomInfo, rabbitRomName, NULL, NULL, NULL, NULL, RabbitInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x4000,
320, 224, 4, 3
};
// Rabbit (Japan, location test)
static struct BurnRomInfo rabbitjtRomDesc[] = {
{ "pvo0_mst_1-28.u82", 0x080000, 0xa1c30c91, 1 | BRF_PRG | BRF_ESS }, // 0 M68ec020 Code
{ "pvo1_mst_1-28.u84", 0x080000, 0x9b7697e6, 1 | BRF_PRG | BRF_ESS }, // 1
{ "pvo2_mst_1-28.u83", 0x080000, 0x9809b825, 1 | BRF_PRG | BRF_ESS }, // 2
{ "pvo3_mst_1-28.u85", 0x080000, 0xce8ebb82, 1 | BRF_PRG | BRF_ESS }, // 3
{ "jfv0.00", 0x400000, 0xb2a4d3d3, 2 | BRF_GRA }, // 4 Sprites
{ "jfv1.01", 0x400000, 0x83f3926e, 2 | BRF_GRA }, // 5
{ "jfv2.02", 0x400000, 0xb264bfb5, 2 | BRF_GRA }, // 6
{ "jfv3.03", 0x400000, 0x3e1a9be2, 2 | BRF_GRA }, // 7
{ "jbg0.40", 0x200000, 0x89662944, 3 | BRF_GRA }, // 8 Background Tiles
{ "jbg1.50", 0x200000, 0x1fc7f6e0, 3 | BRF_GRA }, // 9
{ "jbg2.60", 0x200000, 0xaee265fc, 3 | BRF_GRA }, // 10
{ "jsn0.11", 0x400000, 0xe1f726e8, 4 | BRF_GRA }, // 11 i5000snd Samples
{ "rabbit.nv", 0x000080, 0x73d471ed, 5 | BRF_PRG | BRF_ESS }, // 12 Default EEPROM
};
STD_ROM_PICK(rabbitjt)
STD_ROM_FN(rabbitjt)
struct BurnDriver BurnDrvRabbitjt = {
"rabbitjt", "rabbit", NULL, NULL, "1996",
"Rabbit (Japan, location test)\0", NULL, "Aorn / Electronic Arts", "Miscellaneous",
NULL, NULL, NULL, NULL,
BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_POST90S, GBF_VSFIGHT, 0,
NULL, rabbitjtRomInfo, rabbitjtRomName, NULL, NULL, NULL, NULL, RabbitInputInfo, NULL,
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x4000,
320, 224, 4, 3
};

388
src/burn/snd/i5000.cpp Normal file
View File

@ -0,0 +1,388 @@
// license:BSD-3-Clause
// copyright-holders:hap
/***************************************************************************
i5000.c - Imagetek I5000 sound emulator
Imagetek I5000 is a multi-purpose chip, this covers the sound part.
No official documentation is known to exist. It seems to be a simple
16-channel ADPCM player.
TODO:
- verify that ADPCM is the same as standard OKI ADPCM
- verify volume balance
- sample command 0x0007
- any more sound formats than 3-bit and 4-bit ADPCM?
***************************************************************************/
#include "burnint.h"
#include "i5000.h"
#include "math.h" // floor, pow
struct channel_t
{
bool is_playing;
INT32 signal;
INT32 step;
UINT32 address;
INT32 freq_timer;
INT32 freq_base;
INT32 freq_min;
UINT16 sample;
UINT8 shift_pos;
UINT8 shift_amount;
UINT8 shift_mask;
INT32 vol_r;
INT32 vol_l;
INT32 output_r;
INT32 output_l;
};
static channel_t channels[16];
static UINT16 regs[0x80];
static UINT16 *rom_base;
static UINT32 rom_mask;
static INT32 lut_volume[0x100];
static const INT8 s_index_shift[8] = { -1, -1, -1, -1, 8, 4, 2, 1 };
static INT32 s_diff_lookup[49*16];
// cheap resampler-izer
static INT32 sample_rate;
static INT16 *mixer_buffer_left;
static INT16 *mixer_buffer_right;
static UINT32 nSampleSize;
static INT32 nFractionalPosition;
static INT32 nPosition;
static void compute_tables()
{
static const INT8 nbl2bit[16][4] =
{
{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
};
// loop over all possible steps
for (INT32 step = 0; step <= 48; step++)
{
// compute the step value
INT32 stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
// loop over all nibbles and compute the difference
for (INT32 nib = 0; nib < 16; nib++)
{
s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * (stepval * nbl2bit[nib][1] + stepval/2 * nbl2bit[nib][2] + stepval/4 * nbl2bit[nib][3] + stepval/8);
}
}
}
void i5000sndInit(UINT8 *rom, INT32 clock, INT32 length)
{
memset(channels, 0, sizeof(channels));
memset(regs, 0, sizeof(regs));
// fill volume table
double div = 1.032;
double vol = 2047.0;
for (INT32 i = 0; i < 0x100; i++)
{
lut_volume[i] = vol + 0.5;
vol /= div;
}
lut_volume[0xff] = 0;
compute_tables();
rom_base = (UINT16*)rom;
rom_mask = (length / 2) - 1;
sample_rate = clock / 0x400;
// for resampling
nSampleSize = (UINT32)sample_rate * (1 << 16) / nBurnSoundRate;
nFractionalPosition = 0;
nPosition = 0;
mixer_buffer_left = (INT16*)BurnMalloc(2 * sizeof(INT16) * sample_rate);
mixer_buffer_right = mixer_buffer_left + sample_rate;
}
void i5000sndExit()
{
if (mixer_buffer_left) {
BurnFree(mixer_buffer_left);
mixer_buffer_left = mixer_buffer_right = NULL;
}
}
void i5000sndReset()
{
// stop playing
i5000sndWrite(0x43, 0xffff);
// reset channel regs
for (INT32 i = 0; i < 0x40; i++) {
i5000sndWrite(i, 0);
}
for (INT32 i = 0; i < 16; i++) {
channels[i].signal = -2;
channels[i].step = 0;
}
}
static bool read_sample(int ch)
{
channels[ch].shift_pos &= 0xf;
channels[ch].sample = rom_base[channels[ch].address];
channels[ch].address = (channels[ch].address + 1) & rom_mask;
// handle command
if (channels[ch].sample == 0x7f7f)
{
UINT16 cmd = rom_base[channels[ch].address];
channels[ch].address = (channels[ch].address + 1) & rom_mask;
// volume envelope? or loop sample?
if ((cmd & 0x00ff) == 0x0007)
{
return false;
}
else return false;
}
return true;
}
static inline INT16 clock(INT32 ch, UINT8 nibble)
{
// update the signal
channels[ch].signal += s_diff_lookup[channels[ch].step * 16 + (nibble & 15)];
// clamp to the maximum
if (channels[ch].signal > 2047)
channels[ch].signal = 2047;
else if (channels[ch].signal < -2048)
channels[ch].signal = -2048;
// adjust the step size and clamp
channels[ch].step += s_index_shift[nibble & 7];
if (channels[ch].step > 48)
channels[ch].step = 48;
else if (channels[ch].step < 0)
channels[ch].step = 0;
// return the signal
return channels[ch].signal;
}
void i5000sndUpdate(INT16 *output, INT32 length)
{
INT32 nSamplesNeeded = ((((((sample_rate * 1000) / nBurnFPS) * length) / nBurnSoundLen)) / 10) + 1;
if (nBurnSoundRate < 44100) nSamplesNeeded += 2; // so we don't end up with negative nPosition below
INT16 *lmix = mixer_buffer_left + 5 + nPosition;
INT16 *rmix = mixer_buffer_right + 5 + nPosition;
memset(lmix, 0, nSamplesNeeded * sizeof(INT16));
memset(rmix, 0, nSamplesNeeded * sizeof(INT16));
for (INT32 i = 0; i < (nSamplesNeeded - nPosition); i++)
{
INT32 mix_l = 0;
INT32 mix_r = 0;
// loop over all channels
for (INT32 ch = 0; ch < 16; ch++)
{
if (!channels[ch].is_playing)
continue;
channels[ch].freq_timer -= channels[ch].freq_min;
if (channels[ch].freq_timer > 0)
{
mix_r += channels[ch].output_r;
mix_l += channels[ch].output_l;
continue;
}
channels[ch].freq_timer += channels[ch].freq_base;
int adpcm_data = channels[ch].sample >> channels[ch].shift_pos;
channels[ch].shift_pos += channels[ch].shift_amount;
if (channels[ch].shift_pos & 0x10)
{
if (!read_sample(ch))
{
channels[ch].is_playing = false;
continue;
}
adpcm_data |= (channels[ch].sample << (channels[ch].shift_amount - channels[ch].shift_pos));
}
adpcm_data = clock(ch,adpcm_data & channels[ch].shift_mask);
channels[ch].output_r = adpcm_data * channels[ch].vol_r / 128;
channels[ch].output_l = adpcm_data * channels[ch].vol_l / 128;
mix_r += channels[ch].output_r;
mix_l += channels[ch].output_l;
}
lmix[i] = mix_l / 16;
rmix[i] = mix_r / 16;
}
INT16 *pBufL = mixer_buffer_left + 5;
INT16 *pBufR = mixer_buffer_right + 5;
for (INT32 i = (nFractionalPosition & 0xFFFF0000) >> 15; i < (length << 1); i += 2, nFractionalPosition += nSampleSize) {
INT32 nLeftSample[4] = {0, 0, 0, 0};
INT32 nRightSample[4] = {0, 0, 0, 0};
INT32 nTotalLeftSample, nTotalRightSample;
nLeftSample[0] += (INT32)(pBufL[(nFractionalPosition >> 16) - 3]);
nLeftSample[1] += (INT32)(pBufL[(nFractionalPosition >> 16) - 2]);
nLeftSample[2] += (INT32)(pBufL[(nFractionalPosition >> 16) - 1]);
nLeftSample[3] += (INT32)(pBufL[(nFractionalPosition >> 16) - 0]);
nRightSample[0] += (INT32)(pBufR[(nFractionalPosition >> 16) - 3]);
nRightSample[1] += (INT32)(pBufR[(nFractionalPosition >> 16) - 2]);
nRightSample[2] += (INT32)(pBufR[(nFractionalPosition >> 16) - 1]);
nRightSample[3] += (INT32)(pBufR[(nFractionalPosition >> 16) - 0]);
nTotalLeftSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nLeftSample[0], nLeftSample[1], nLeftSample[2], nLeftSample[3]);
nTotalRightSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nRightSample[0], nRightSample[1], nRightSample[2], nRightSample[3]);
nTotalLeftSample = BURN_SND_CLIP(nTotalLeftSample);
nTotalRightSample = BURN_SND_CLIP(nTotalRightSample);
output[i + 0] = nTotalLeftSample;
output[i + 1] = nTotalRightSample;
}
if (length >= nBurnSoundLen) {
INT32 nExtraSamples = nSamplesNeeded - (nFractionalPosition >> 16);
for (INT32 i = -4; i < nExtraSamples; i++) {
pBufL[i] = pBufL[(nFractionalPosition >> 16) + i];
pBufR[i] = pBufR[(nFractionalPosition >> 16) + i];
}
nFractionalPosition &= 0xFFFF;
nPosition = nExtraSamples;
}
}
void i5000sndWrite(INT32 offset, UINT16 data)
{
UINT8 reg = offset;
if (reg < 0x40)
{
INT32 ch = reg >> 2;
switch (reg & 3)
{
case 2:
channels[ch].freq_base = (0x1ff - (data & 0xff)) << (~data >> 8 & 3);
break;
case 3:
channels[ch].vol_r = lut_volume[data & 0xff];
channels[ch].vol_l = lut_volume[data >> 8 & 0xff];
break;
}
}
else
{
switch (reg)
{
case 0x42:
for (INT32 ch = 0; ch < 16; ch++)
{
if (data & (1 << ch) && !channels[ch].is_playing)
{
UINT32 address = regs[ch << 2 | 1] << 16 | regs[ch << 2];
UINT16 start = rom_base[(address + 0) & rom_mask];
UINT16 param = rom_base[(address + 1) & rom_mask];
if (start != 0x7f7f)
{
continue;
}
switch (param)
{
case 0x0104:
case 0x0304: // same?
channels[ch].freq_min = 0x140;
channels[ch].shift_amount = 3;
channels[ch].shift_mask = 0xe;
break;
default:
case 0x0184:
channels[ch].freq_min = 0x100;
channels[ch].shift_amount = 4;
channels[ch].shift_mask = 0xf;
break;
}
channels[ch].address = (address + 4) & rom_mask;
channels[ch].freq_timer = 0;
channels[ch].shift_pos = 0;
channels[ch].signal = -2;
channels[ch].step = 0;
channels[ch].is_playing = read_sample(ch);
}
}
break;
case 0x43:
for (INT32 ch = 0; ch < 16; ch++)
{
if (data & (1 << ch))
channels[ch].is_playing = false;
}
break;
}
}
regs[reg] = data;
}
UINT16 i5000sndRead(INT32 offset)
{
UINT16 ret = 0;
switch (offset)
{
// channel active state
case 0x42:
for (INT32 ch = 0; ch < 16; ch++)
{
if (channels[ch].is_playing)
ret |= (1 << ch);
}
break;
}
return ret;
}
void i5000sndScan(INT32 nAction, INT32 *pnMin)
{
if (pnMin) {
*pnMin = 0x029702;
}
if (nAction & ACB_DRIVER_DATA) {
SCAN_VAR(channels);
SCAN_VAR(regs);
}
}

7
src/burn/snd/i5000.h Normal file
View File

@ -0,0 +1,7 @@
void i5000sndInit(UINT8 *rom, INT32 clock, INT32 length);
void i5000sndExit();
void i5000sndReset();
void i5000sndUpdate(INT16 *output, INT32 length);
void i5000sndWrite(INT32 offset, UINT16 data);
UINT16 i5000sndRead(INT32 offset);
void i5000sndScan(INT32 nAction, INT32 *pnMin);