mirror of
https://github.com/holub/mame
synced 2025-06-04 11:56:28 +03:00

Instead, they are identified by the region they were loaded in. This generally means one disk per region. get_disk_handle() now takes a region name in place of an index. Updated all callers to do this. The SCSI modules in particular posed a challenge to make this work, so watch out for potential bugs there. Changed the IDE interfaces to default to choosing the region with the same tag as the device for its master disk (assuming no slave). Added support for specifying explicit master/slave disk regions as part of the configuration, though slave disks are still not supported yet. Change the laserdisc interface to no longer require a disk number or a custom sound device. Both are now assumed to be tagged the same as the laserdisc device. Updated all drivers accordingly.
914 lines
18 KiB
C
914 lines
18 KiB
C
/* LSI Logic LSI53C810A PCI to SCSI I/O Processor */
|
|
|
|
#include "driver.h"
|
|
#include "deprecat.h"
|
|
#include "53c810.h"
|
|
|
|
#define DMA_MAX_ICOUNT 512 /* Maximum number of DMA Scripts opcodes to run */
|
|
#define DASM_OPCODES 0
|
|
|
|
static SCSIInstance *devices[8]; /* SCSI IDs 0-7 */
|
|
static const struct LSI53C810interface *intf;
|
|
static UINT8 last_id;
|
|
|
|
static struct {
|
|
UINT8 scntl0;
|
|
UINT8 scntl1;
|
|
UINT8 scntl2;
|
|
UINT8 scntl3;
|
|
UINT8 scid;
|
|
UINT8 socl;
|
|
UINT8 istat;
|
|
UINT8 dstat;
|
|
UINT8 sstat0;
|
|
UINT8 sstat1;
|
|
UINT8 sstat2;
|
|
UINT8 dien;
|
|
UINT8 dcntl;
|
|
UINT8 dmode;
|
|
UINT32 temp;
|
|
UINT32 dsa;
|
|
UINT32 dsp;
|
|
UINT32 dsps;
|
|
UINT32 dcmd;
|
|
UINT8 sien0;
|
|
UINT8 sien1;
|
|
UINT8 stime0;
|
|
UINT8 respid;
|
|
UINT8 stest1;
|
|
UINT8 scratch_a[4];
|
|
UINT8 scratch_b[4];
|
|
int dma_icount;
|
|
int halted;
|
|
int carry;
|
|
UINT32 (* fetch)(UINT32 dsp);
|
|
void (* irq_callback)(running_machine *machine);
|
|
void (* dma_callback)(UINT32, UINT32, int, int);
|
|
} lsi810;
|
|
|
|
static void (* dma_opcode[256])(void);
|
|
|
|
|
|
INLINE UINT32 FETCH(void)
|
|
{
|
|
UINT32 r = intf->fetch(lsi810.dsp);
|
|
lsi810.dsp += 4;
|
|
return r;
|
|
}
|
|
|
|
#ifdef UNUSED_FUNCTION
|
|
static UINT32 sign_extend24(UINT32 val)
|
|
{
|
|
if (val & 0x00800000)
|
|
val |= 0xFF000000;
|
|
else
|
|
val &= ~0xFF000000;
|
|
return val;
|
|
}
|
|
#endif
|
|
|
|
static void dmaop_invalid(void)
|
|
{
|
|
fatalerror("LSI53C810: Invalid SCRIPTS DMA opcode %08X at %08X", lsi810.dcmd, lsi810.dsp);
|
|
}
|
|
|
|
static void dmaop_move_memory(void)
|
|
{
|
|
UINT32 src = FETCH();
|
|
UINT32 dst = FETCH();
|
|
int count;
|
|
|
|
count = lsi810.dcmd & 0xffffff;
|
|
if(intf->dma_callback != NULL) {
|
|
intf->dma_callback(src, dst, count, 1);
|
|
}
|
|
}
|
|
|
|
static void dmaop_interrupt(void)
|
|
{
|
|
if(lsi810.dcmd & 0x100000) {
|
|
fatalerror("LSI53C810: INTFLY opcode not implemented");
|
|
}
|
|
lsi810.dsps = FETCH();
|
|
|
|
lsi810.istat |= 0x1; /* DMA interrupt pending */
|
|
lsi810.dstat |= 0x4; /* SIR (SCRIPTS Interrupt Instruction Received) */
|
|
|
|
if(intf->irq_callback != NULL) {
|
|
intf->irq_callback(Machine, 1);
|
|
}
|
|
lsi810.dma_icount = 0;
|
|
lsi810.halted = 1;
|
|
}
|
|
|
|
static void dmaop_block_move(void)
|
|
{
|
|
UINT32 address;
|
|
UINT32 count;
|
|
INT32 dsps;
|
|
|
|
address = FETCH();
|
|
count = lsi810.dcmd & 0x00ffffff;
|
|
|
|
// normal indirect
|
|
if (lsi810.dcmd & 0x20000000)
|
|
address = intf->fetch(address);
|
|
|
|
// table indirect
|
|
if (lsi810.dcmd & 0x10000000)
|
|
{
|
|
dsps = (INT32)address&0xffffff;
|
|
// sign extend
|
|
if (dsps & 0x00800000)
|
|
{
|
|
dsps |= 0xff000000;
|
|
}
|
|
logerror("table offset: %x, DSA = %x\n", dsps, lsi810.dsa);
|
|
dsps += lsi810.dsa;
|
|
|
|
logerror("Loading from table at %x\n", dsps);
|
|
count = lsi810.fetch(dsps);
|
|
address = lsi810.fetch(dsps+4);
|
|
}
|
|
|
|
logerror("block move: address %x count %x phase %x\n", address, count, (lsi810.dcmd>>24)&7);
|
|
|
|
if (lsi810.scntl0 & 0x01)
|
|
{
|
|
/* target mode */
|
|
fatalerror("LSI53C810: dmaop_block_move not implemented in target mode");
|
|
}
|
|
else
|
|
{
|
|
/* initiator mode */
|
|
logerror("53c810: block_move not actually implemented\n");
|
|
}
|
|
}
|
|
|
|
static void dmaop_select(void)
|
|
{
|
|
UINT32 operand;
|
|
|
|
operand = FETCH();
|
|
|
|
if (lsi810.scntl0 & 0x01)
|
|
{
|
|
/* target mode */
|
|
logerror("LSI53C810: reselect ID #%d\n", (lsi810.dcmd >> 16) & 0x07);
|
|
}
|
|
else
|
|
{
|
|
/* initiator mode */
|
|
logerror("53c810: SELECT: our ID %d, target ID %d\n", lsi810.scid&7, (lsi810.dcmd>>16)&7);
|
|
|
|
lsi810.sstat1 &= ~0x07; // clear current bus phase
|
|
if (lsi810.dcmd & 0x01000000) // select with ATN
|
|
{
|
|
mame_printf_debug("53c810: want select with ATN, setting message phase\n");
|
|
lsi810.sstat1 |= 0x7; // ATN means we want message in phase
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dmaop_wait_disconnect(void)
|
|
{
|
|
UINT32 operand;
|
|
|
|
operand = FETCH();
|
|
|
|
if (lsi810.scntl0 & 0x01)
|
|
{
|
|
/* target mode */
|
|
fatalerror("LSI53C810: dmaop_wait_disconnect not implemented in target mode");
|
|
}
|
|
else
|
|
{
|
|
/* initiator mode */
|
|
fatalerror("LSI53C810: dmaop_wait_disconnect not implemented");
|
|
}
|
|
}
|
|
|
|
static void dmaop_wait_reselect(void)
|
|
{
|
|
UINT32 operand;
|
|
|
|
operand = FETCH();
|
|
|
|
if (lsi810.scntl0 & 0x01)
|
|
{
|
|
/* target mode */
|
|
fatalerror("LSI53C810: dmaop_wait_reselect not implemented in target mode");
|
|
}
|
|
else
|
|
{
|
|
/* initiator mode */
|
|
fatalerror("LSI53C810: dmaop_wait_reselect not implemented");
|
|
}
|
|
}
|
|
|
|
static void dmaop_set(void)
|
|
{
|
|
UINT32 operand;
|
|
|
|
operand = FETCH();
|
|
|
|
/* initiator mode */
|
|
if (lsi810.dcmd & 0x8)
|
|
{
|
|
// set ATN in SOCL
|
|
lsi810.socl |= 0x08;
|
|
}
|
|
if (lsi810.dcmd & 0x40)
|
|
{
|
|
// set ACK in SOCL
|
|
lsi810.socl |= 0x40;
|
|
}
|
|
if (lsi810.dcmd & 0x200)
|
|
{
|
|
// set target mode
|
|
lsi810.scntl0 |= 0x01;
|
|
}
|
|
if (lsi810.dcmd & 0x400)
|
|
{
|
|
// set carry in ALU
|
|
lsi810.carry = 1;
|
|
}
|
|
}
|
|
|
|
static void dmaop_clear(void)
|
|
{
|
|
UINT32 operand;
|
|
|
|
operand = FETCH();
|
|
|
|
/* initiator mode */
|
|
if (lsi810.dcmd & 0x8)
|
|
{
|
|
// clear ATN in SOCL
|
|
lsi810.socl &= ~0x08;
|
|
}
|
|
if (lsi810.dcmd & 0x40)
|
|
{
|
|
// clear ACK in SOCL
|
|
lsi810.socl &= ~0x40;
|
|
}
|
|
if (lsi810.dcmd & 0x200)
|
|
{
|
|
// clear target mode
|
|
lsi810.scntl0 &= ~0x01;
|
|
}
|
|
if (lsi810.dcmd & 0x400)
|
|
{
|
|
// clear carry in ALU
|
|
lsi810.carry = 0;
|
|
}
|
|
}
|
|
|
|
static void dmaop_move_from_sfbr(void)
|
|
{
|
|
fatalerror("LSI53C810: dmaop_move_from_sfbr not implemented in target mode");
|
|
}
|
|
|
|
static void dmaop_move_to_sfbr(void)
|
|
{
|
|
fatalerror("LSI53C810: dmaop_move_to_sfbr not implemented");
|
|
}
|
|
|
|
static void dmaop_read_modify_write(void)
|
|
{
|
|
fatalerror("LSI53C810: dmaop_read_modify_write not implemented");
|
|
}
|
|
|
|
static int scripts_compute_branch(void)
|
|
{
|
|
int dtest, ptest, wanted, passed;
|
|
|
|
// |jump if true
|
|
// 878b0000 ||compare data
|
|
// 1000 0111 1000 1011 0000 0000 0000 0000
|
|
// | |rel ||wait valid phase
|
|
// | |compare phase
|
|
// |desired phase: message in
|
|
|
|
if (lsi810.dcmd & 0x00200000)
|
|
{
|
|
fatalerror("LSI53C810: jump with carry test not implemented");
|
|
}
|
|
|
|
if (lsi810.dcmd & 0x00100000)
|
|
{
|
|
fatalerror("LSI53C810: jump with interrupt on the fly not implemented");
|
|
}
|
|
|
|
// set desired result to take jump
|
|
wanted = (lsi810.dcmd & 0x00080000) ? 1 : 0;
|
|
// default to passing the tests in case they're disabled
|
|
dtest = ptest = wanted;
|
|
|
|
// phase test?
|
|
if (lsi810.dcmd & 0x00020000)
|
|
{
|
|
logerror("53c810: phase test. current: %x. target: %x\n", lsi810.sstat1 & 7, (lsi810.dcmd>>24)&7);
|
|
|
|
// do the phases match?
|
|
if (((lsi810.dcmd>>24)&7) == (lsi810.sstat1 & 7))
|
|
{
|
|
ptest = 1;
|
|
}
|
|
else
|
|
{
|
|
ptest = 0;
|
|
}
|
|
}
|
|
|
|
// data test?
|
|
if (lsi810.dcmd & 0x00040000)
|
|
{
|
|
logerror("53c810: data test. target: %x [not yet implemented]\n", lsi810.dcmd&0xff);
|
|
}
|
|
|
|
// if all conditions go, take the jump
|
|
passed = 0;
|
|
if ((ptest == dtest) && (dtest == wanted))
|
|
{
|
|
passed = 1;
|
|
}
|
|
|
|
logerror("53c810: phase test %d data test %d wanted %d => pass %d\n", ptest, dtest, wanted, passed);
|
|
|
|
return passed;
|
|
}
|
|
|
|
static UINT32 scripts_get_jump_dest(void)
|
|
{
|
|
INT32 dsps;
|
|
UINT32 dest;
|
|
|
|
dsps = FETCH();
|
|
|
|
/* relative or absolute addressing? */
|
|
if (lsi810.dcmd & 0x00800000)
|
|
{
|
|
// sign-extend the 24-bit value
|
|
if (dsps & 0x00800000)
|
|
{
|
|
dsps |= 0xff000000;
|
|
}
|
|
|
|
logerror("dsps = %x, dsp = %x\n", dsps, lsi810.dsp);
|
|
dsps += lsi810.dsp;
|
|
}
|
|
|
|
dest = (UINT32)dsps;
|
|
|
|
logerror("cur DSP %x, dest %x\n", lsi810.dsp, dest);
|
|
|
|
return dest;
|
|
}
|
|
|
|
static void dmaop_jump(void)
|
|
{
|
|
if (scripts_compute_branch())
|
|
{
|
|
lsi810.dsp = scripts_get_jump_dest();
|
|
}
|
|
else
|
|
{
|
|
FETCH(); // skip operand to continue on
|
|
}
|
|
}
|
|
|
|
static void dmaop_call(void)
|
|
{
|
|
if (scripts_compute_branch())
|
|
{
|
|
// save return address
|
|
lsi810.temp = lsi810.dsp;
|
|
|
|
// and go
|
|
lsi810.dsp = scripts_get_jump_dest();
|
|
}
|
|
else
|
|
{
|
|
FETCH(); // skip operand to continue on
|
|
}
|
|
}
|
|
|
|
static void dmaop_return(void)
|
|
{
|
|
// is this correct? return only happens if the condition is true?
|
|
if (scripts_compute_branch())
|
|
{
|
|
// restore return address
|
|
lsi810.dsp = lsi810.temp;
|
|
}
|
|
else
|
|
{
|
|
FETCH(); // skip operand to continue on
|
|
}
|
|
}
|
|
|
|
static void dmaop_store(void)
|
|
{
|
|
fatalerror("LSI53C810: dmaop_store not implemented");
|
|
}
|
|
|
|
static void dmaop_load(void)
|
|
{
|
|
fatalerror("LSI53C810: dmaop_load not implemented");
|
|
}
|
|
|
|
|
|
|
|
static void dma_exec(void)
|
|
{
|
|
lsi810.dma_icount = DMA_MAX_ICOUNT;
|
|
|
|
while(lsi810.dma_icount > 0)
|
|
{
|
|
int op;
|
|
|
|
if (DASM_OPCODES)
|
|
{
|
|
char buf[256];
|
|
lsi53c810_dasm(buf, lsi810.dsp);
|
|
logerror("0x%08X: %s\n", lsi810.dsp, buf);
|
|
}
|
|
|
|
lsi810.dcmd = FETCH();
|
|
|
|
op = (lsi810.dcmd >> 24) & 0xff;
|
|
dma_opcode[op]();
|
|
|
|
lsi810.dma_icount--;
|
|
}
|
|
}
|
|
|
|
READ8_HANDLER( lsi53c810_reg_r )
|
|
{
|
|
logerror("53c810: read reg %d:0x%x (PC=%x)\n", offset, offset, activecpu_get_pc());
|
|
switch(offset)
|
|
{
|
|
case 0x00: /* SCNTL0 */
|
|
return lsi810.scntl0;
|
|
case 0x01: /* SCNTL1 */
|
|
return lsi810.scntl1;
|
|
case 0x02: /* SCNTL2 */
|
|
return lsi810.scntl2;
|
|
case 0x03: /* SCNTL3 */
|
|
return lsi810.scntl3;
|
|
case 0x04: /* SCID */
|
|
return lsi810.scid;
|
|
case 0x09: /* SOCL */
|
|
return lsi810.socl;
|
|
case 0x0c: /* DSTAT */
|
|
return lsi810.dstat;
|
|
case 0x0d: /* SSTAT0 */
|
|
return lsi810.sstat0;
|
|
case 0x0e: /* SSTAT1 */
|
|
return lsi810.sstat1;
|
|
case 0x0f: /* SSTAT2 */
|
|
return lsi810.sstat2;
|
|
case 0x10: /* DSA [7-0] */
|
|
return lsi810.dsa & 0xff;
|
|
case 0x11: /* DSA [15-8] */
|
|
return (lsi810.dsa >> 8) & 0xff;
|
|
case 0x12: /* DSA [23-16] */
|
|
return (lsi810.dsa >> 16) & 0xff;
|
|
case 0x13: /* DSA [31-24] */
|
|
return (lsi810.dsa >> 24) & 0xff;
|
|
case 0x14: /* ISTAT */
|
|
// clear the interrupt on service
|
|
if(intf->irq_callback != NULL)
|
|
{
|
|
intf->irq_callback(machine, 0);
|
|
}
|
|
|
|
return lsi810.istat;
|
|
case 0x2c: /* DSP [7-0] */
|
|
return lsi810.dsp & 0xff;
|
|
case 0x2d: /* DSP [15-8] */
|
|
return (lsi810.dsp >> 8) & 0xff;
|
|
case 0x2e: /* DSP [23-16] */
|
|
return (lsi810.dsp >> 16) & 0xff;
|
|
case 0x2f: /* DSP [31-24] */
|
|
return (lsi810.dsp >> 24) & 0xff;
|
|
case 0x34: /* SCRATCH A */
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
return lsi810.scratch_a[offset % 4];
|
|
case 0x39: /* DIEN */
|
|
return lsi810.dien;
|
|
case 0x3b: /* DCNTL */
|
|
return lsi810.dcntl;
|
|
case 0x40: /* SIEN0 */
|
|
return lsi810.sien0;
|
|
case 0x41: /* SIEN1 */
|
|
return lsi810.sien1;
|
|
case 0x48: /* STIME0 */
|
|
return lsi810.stime0;
|
|
case 0x4a: /* RESPID */
|
|
return lsi810.respid;
|
|
case 0x4d: /* STEST1 */
|
|
return lsi810.stest1;
|
|
case 0x5c: /* SCRATCH B */
|
|
case 0x5d:
|
|
case 0x5e:
|
|
case 0x5f:
|
|
return lsi810.scratch_b[offset % 4];
|
|
|
|
default:
|
|
fatalerror("LSI53C810: reg_r: Unknown reg %02X", offset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
WRITE8_HANDLER( lsi53c810_reg_w )
|
|
{
|
|
logerror("53c810: %02x to reg %d:0x%x (PC=%x)\n", data, offset, offset, activecpu_get_pc());
|
|
switch(offset)
|
|
{
|
|
case 0x00: /* SCNTL0 */
|
|
lsi810.scntl0 = data;
|
|
break;
|
|
case 0x01: /* SCNTL1 */
|
|
lsi810.scntl1 = data;
|
|
break;
|
|
case 0x02: /* SCNTL2 */
|
|
lsi810.scntl2 = data;
|
|
break;
|
|
case 0x03: /* SCNTL3 */
|
|
lsi810.scntl3 = data;
|
|
break;
|
|
case 0x04: /* SCID */
|
|
lsi810.scid = data;
|
|
break;
|
|
case 0x09: /* SOCL */
|
|
lsi810.socl = data;
|
|
break;
|
|
case 0x0d: /* SSTAT0 */
|
|
lsi810.sstat0 = data;
|
|
break;
|
|
case 0x0e: /* SSTAT1 */
|
|
lsi810.sstat1 = data;
|
|
break;
|
|
case 0x0f: /* SSTAT2 */
|
|
lsi810.sstat2 = data;
|
|
break;
|
|
case 0x10: /* DSA [7-0] */
|
|
lsi810.dsa &= 0xffffff00;
|
|
lsi810.dsa |= data;
|
|
break;
|
|
case 0x11: /* DSA [15-8] */
|
|
lsi810.dsa &= 0xffff00ff;
|
|
lsi810.dsa |= data << 8;
|
|
break;
|
|
case 0x12: /* DSA [23-16] */
|
|
lsi810.dsa &= 0xff00ffff;
|
|
lsi810.dsa |= data << 16;
|
|
break;
|
|
case 0x13: /* DSA [31-24] */
|
|
lsi810.dsa &= 0x00ffffff;
|
|
lsi810.dsa |= data << 24;
|
|
break;
|
|
case 0x14: /* ISTAT */
|
|
lsi810.istat = data;
|
|
break;
|
|
case 0x2c: /* DSP [7-0] */
|
|
lsi810.dsp &= 0xffffff00;
|
|
lsi810.dsp |= data;
|
|
break;
|
|
case 0x2d: /* DSP [15-8] */
|
|
lsi810.dsp &= 0xffff00ff;
|
|
lsi810.dsp |= data << 8;
|
|
break;
|
|
case 0x2e: /* DSP [23-16] */
|
|
lsi810.dsp &= 0xff00ffff;
|
|
lsi810.dsp |= data << 16;
|
|
break;
|
|
case 0x2f: /* DSP [31-24] */
|
|
lsi810.dsp &= 0x00ffffff;
|
|
lsi810.dsp |= data << 24;
|
|
lsi810.halted = 0;
|
|
if((lsi810.dmode & 0x1) == 0 && !lsi810.halted) {
|
|
dma_exec();
|
|
}
|
|
break;
|
|
case 0x34: /* SCRATCH A */
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
lsi810.scratch_a[offset % 4] = data;
|
|
break;
|
|
case 0x38: /* DMODE */
|
|
lsi810.dmode = data;
|
|
break;
|
|
case 0x39: /* DIEN */
|
|
lsi810.dien = data;
|
|
break;
|
|
case 0x3b: /* DCNTL */
|
|
lsi810.dcntl = data;
|
|
|
|
if(lsi810.dcntl & 0x14 && !lsi810.halted) /* single-step & start DMA */
|
|
{
|
|
int op;
|
|
lsi810.dcmd = FETCH();
|
|
op = (lsi810.dcmd >> 24) & 0xff;
|
|
dma_opcode[op]();
|
|
|
|
lsi810.istat |= 0x3; /* DMA interrupt pending */
|
|
lsi810.dstat |= 0x8; /* SSI (Single Step Interrupt) */
|
|
if(intf->irq_callback != NULL) {
|
|
intf->irq_callback(machine, 1);
|
|
}
|
|
}
|
|
else if(lsi810.dcntl & 0x04 && !lsi810.halted) /* manual start DMA */
|
|
{
|
|
dma_exec();
|
|
}
|
|
break;
|
|
case 0x40: /* SIEN0 */
|
|
lsi810.sien0 = data;
|
|
break;
|
|
case 0x41: /* SIEN1 */
|
|
lsi810.sien1 = data;
|
|
break;
|
|
case 0x48: /* STIME0 */
|
|
lsi810.stime0 = data;
|
|
break;
|
|
case 0x4a: /* RESPID */
|
|
lsi810.respid = data;
|
|
break;
|
|
case 0x4d: /* STEST1 */
|
|
lsi810.stest1 = data;
|
|
break;
|
|
case 0x5c: /* SCRATCH B */
|
|
case 0x5d:
|
|
case 0x5e:
|
|
case 0x5f:
|
|
lsi810.scratch_b[offset % 4] = data;
|
|
break;
|
|
|
|
default:
|
|
fatalerror("LSI53C810: reg_w: Unknown reg %02X, %02X", offset, data);
|
|
}
|
|
}
|
|
|
|
static void add_opcode(UINT8 op, UINT8 mask, void (* handler)(void))
|
|
{
|
|
int i;
|
|
for(i=0; i < 256; i++) {
|
|
if((i & mask) == op) {
|
|
dma_opcode[i] = handler;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void lsi53c810_init(const struct LSI53C810interface *interface)
|
|
{
|
|
int i;
|
|
|
|
// save interface pointer for later
|
|
intf = interface;
|
|
|
|
memset(&lsi810, 0, sizeof(lsi810));
|
|
for(i = 0; i < 256; i++)
|
|
{
|
|
dma_opcode[i] = dmaop_invalid;
|
|
}
|
|
|
|
add_opcode(0x00, 0xc0, dmaop_block_move);
|
|
add_opcode(0x40, 0xf8, dmaop_select);
|
|
add_opcode(0x48, 0xf8, dmaop_wait_disconnect);
|
|
add_opcode(0x50, 0xf8, dmaop_wait_reselect);
|
|
add_opcode(0x58, 0xf8, dmaop_set);
|
|
add_opcode(0x60, 0xf8, dmaop_clear);
|
|
add_opcode(0x68, 0xf8, dmaop_move_from_sfbr);
|
|
add_opcode(0x70, 0xf8, dmaop_move_to_sfbr);
|
|
add_opcode(0x78, 0xf8, dmaop_read_modify_write);
|
|
add_opcode(0x80, 0xf8, dmaop_jump);
|
|
add_opcode(0x88, 0xf8, dmaop_call);
|
|
add_opcode(0x90, 0xf8, dmaop_return);
|
|
add_opcode(0x98, 0xf8, dmaop_interrupt);
|
|
add_opcode(0xc0, 0xfe, dmaop_move_memory);
|
|
add_opcode(0xe0, 0xed, dmaop_store);
|
|
add_opcode(0xe1, 0xed, dmaop_load);
|
|
|
|
memset(devices, 0, sizeof(devices));
|
|
|
|
// try to open the devices
|
|
for (i = 0; i < interface->scsidevs->devs_present; i++)
|
|
{
|
|
SCSIAllocInstance( interface->scsidevs->devices[i].scsiClass, &devices[interface->scsidevs->devices[i].scsiID], interface->scsidevs->devices[i].diskregion );
|
|
}
|
|
}
|
|
|
|
extern void lsi53c810_exit(const struct LSI53C810interface *interface)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < interface->scsidevs->devs_present; i++)
|
|
{
|
|
SCSIDeleteInstance( devices[interface->scsidevs->devices[i].scsiID] );
|
|
}
|
|
}
|
|
|
|
void lsi53c810_read_data(int bytes, UINT8 *pData)
|
|
{
|
|
if (devices[last_id])
|
|
{
|
|
SCSIReadData( devices[last_id], pData, bytes);
|
|
}
|
|
else
|
|
{
|
|
logerror("lsi53c810: read unknown device SCSI ID %d\n", last_id);
|
|
}
|
|
}
|
|
|
|
void lsi53c810_write_data(int bytes, UINT8 *pData)
|
|
{
|
|
if (devices[last_id])
|
|
{
|
|
SCSIWriteData( devices[last_id], pData, bytes );
|
|
}
|
|
else
|
|
{
|
|
logerror("lsi53c810: write to unknown device SCSI ID %d\n", last_id);
|
|
}
|
|
}
|
|
|
|
void *lsi53c810_get_device(int id)
|
|
{
|
|
void *ret;
|
|
|
|
if (devices[id])
|
|
{
|
|
logerror("lsi53c810: fetching dev pointer for SCSI ID %d\n", id);
|
|
SCSIGetDevice( devices[id], &ret );
|
|
|
|
return ret;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*************************************
|
|
*
|
|
* Disassembler
|
|
*
|
|
*************************************/
|
|
|
|
static UINT32 lsi53c810_dasm_fetch(UINT32 pc)
|
|
{
|
|
return intf->fetch(pc);
|
|
}
|
|
|
|
unsigned lsi53c810_dasm(char *buf, UINT32 pc)
|
|
{
|
|
unsigned result = 0;
|
|
const char *op_mnemonic = NULL;
|
|
UINT32 op = lsi53c810_dasm_fetch(pc);
|
|
UINT32 dest;
|
|
int i;
|
|
|
|
static const char *const phases[] =
|
|
{
|
|
"DATA_OUT", "DATA_IN", "CMD", "STATUS",
|
|
"RESERVED_OUT??", "RESERVED_IN??", "MSG_OUT", "MSG_IN"
|
|
};
|
|
|
|
if ((op & 0xF8000000) == 0x40000000)
|
|
{
|
|
/* SELECT */
|
|
dest = lsi53c810_dasm_fetch(pc + 4);
|
|
|
|
buf += sprintf(buf, "SELECT%s %d, 0x%08X",
|
|
(op & 0x01000000) ? " ATN" : "",
|
|
(op >> 16) & 0x07,
|
|
dest);
|
|
|
|
result = 8;
|
|
}
|
|
else if (((op & 0xF8000000) == 0x58000000)
|
|
| ((op & 0xF8000000) == 0x60000000))
|
|
{
|
|
static const struct
|
|
{
|
|
UINT32 flag;
|
|
const char *text;
|
|
} flags[] =
|
|
{
|
|
{ 0x00000008, "ATN" },
|
|
{ 0x00000040, "ACK" },
|
|
{ 0x00000200, "TARGET" },
|
|
{ 0x00000400, "CARRY" }
|
|
};
|
|
int need_cojunction = FALSE;
|
|
|
|
/* SET/CLEAR */
|
|
switch(op & 0xF8000000)
|
|
{
|
|
case 0x58000000: op_mnemonic = "SET"; break;
|
|
case 0x60000000: op_mnemonic = "CLEAR"; break;
|
|
}
|
|
|
|
buf += sprintf(buf, "%s ", op_mnemonic);
|
|
need_cojunction = FALSE;
|
|
|
|
for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++)
|
|
{
|
|
if (op & flags[i].flag)
|
|
{
|
|
if (need_cojunction)
|
|
buf += sprintf(buf, " AND ");
|
|
else
|
|
need_cojunction = TRUE;
|
|
buf += sprintf(buf, "%s", flags[i].text);
|
|
}
|
|
}
|
|
}
|
|
else if (((op & 0xF8000000) == 0x80000000)
|
|
| ((op & 0xF8000000) == 0x88000000)
|
|
| ((op & 0xF8000000) == 0x98000000))
|
|
{
|
|
/* JUMP/CALL/INT */
|
|
switch(op & 0xF8000000)
|
|
{
|
|
case 0x80000000: op_mnemonic = "JUMP"; break;
|
|
case 0x88000000: op_mnemonic = "CALL"; break;
|
|
case 0x98000000: op_mnemonic = "INT"; break;
|
|
}
|
|
|
|
dest = lsi53c810_dasm_fetch(pc + 4);
|
|
|
|
if (op & 0x00800000)
|
|
{
|
|
/* relative */
|
|
if (dest & 0x00800000)
|
|
dest |= 0xFF000000;
|
|
else
|
|
dest &= 0x00FFFFFF;
|
|
dest = (pc + 8) + dest;
|
|
buf += sprintf(buf, "%s REL(0x%08X)", op_mnemonic, dest);
|
|
}
|
|
else
|
|
{
|
|
/* absolute */
|
|
buf += sprintf(buf, "%s 0x%08X", op_mnemonic, dest);
|
|
}
|
|
|
|
switch(op & 0x000B0000)
|
|
{
|
|
case 0x00000000:
|
|
buf += sprintf(buf, ", NOT??");
|
|
break;
|
|
|
|
case 0x00080000:
|
|
break;
|
|
|
|
case 0x00020000:
|
|
case 0x00030000:
|
|
case 0x000A0000:
|
|
case 0x000B0000:
|
|
buf += sprintf(buf, ", %s%s %s",
|
|
(op & 0x00010000) ? "WHEN" : "IF",
|
|
(op & 0x00080000) ? "" : " NOT",
|
|
phases[(op >> 24) & 0x07]);
|
|
break;
|
|
|
|
default:
|
|
fatalerror("unknown op 0x%08X", op);
|
|
break;
|
|
}
|
|
result = 8;
|
|
}
|
|
else if ((op & 0xE0000000) == 0x00000000)
|
|
{
|
|
/* MOVE FROM */
|
|
dest = lsi53c810_dasm_fetch(pc + 4);
|
|
|
|
buf += sprintf(buf, "MOVE FROM 0x%08X, WHEN %s",
|
|
dest, phases[(op >> 24) & 0x07]);
|
|
|
|
result = 8;
|
|
}
|
|
else if ((op & 0xE0000000) == 0x20000000)
|
|
{
|
|
/* MOVE PTR */
|
|
dest = lsi53c810_dasm_fetch(pc + 4);
|
|
|
|
buf += sprintf(buf, "MOVE 0x%08X, PTR 0x%08X, WHEN %s",
|
|
(op & 0x00FFFFFF), dest, phases[(op >> 24) & 0x07]);
|
|
|
|
result = 8;
|
|
}
|
|
else
|
|
{
|
|
fatalerror("unknown op 0x%08X", op);
|
|
}
|
|
return result;
|
|
}
|
|
|