The NCR 53C810 is now threaded;

Reverted my IDIV fixes - fixes font glitches in Windows XP and possibly other things as well;
Slight fix to line repeat detection in pclog_ex().
This commit is contained in:
OBattler
2017-12-16 19:46:07 +01:00
parent 3a32bda6dc
commit 31153f20d4
5 changed files with 506 additions and 264 deletions

View File

@@ -463,31 +463,28 @@ int divl(uint32_t val)
}
int idivl(int32_t val)
{
uint64_t templ;
int64_t tempsrc, tempws, tempws2 = 0;
int64_t num, quo;
int32_t rem, quo32;
if (val == 0) {
divexcp(); /* Divide by zero. */
return 1;
}
if (val==0)
{
divexcp();
return 1;
}
templ = (uint64_t) EDX;
templ = (templ << 32) | EAX;
tempsrc = (int64_t) templ;
tempws = tempsrc / val;
num=(((uint64_t)EDX)<<32)|EAX;
quo=num/val;
rem=num%val;
quo32=(int32_t)(quo&0xFFFFFFFF);
if ((tempws > 2147483647LL) || (tempws < -2147483648LL)) {
divexcp();
return 1;
}
tempws = (int32_t) tempws;
tempws2 = (int32_t) (templ % val);
EDX = (int32_t) tempws2;
EAX = (int32_t) tempws;
return 0;
if (quo!=(int64_t)quo32)
{
divexcp();
return 1;
}
EDX=rem;
EAX=quo32;
return 0;
}

View File

@@ -84,8 +84,12 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs)
while (block)
{
if (a == block->cmp)
break;
else if (a < block->cmp)
{
if (!((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) &&
((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)))
break;
}
if (a < block->cmp)
block = block->left;
else
block = block->right;

View File

@@ -64,9 +64,10 @@ static int opSETALC(uint32_t fetchdat)
static int opF6_a16(uint32_t fetchdat)
{
int32_t tempsrc, tempdst, tempws, tempws2 = 0;
int tempws, tempws2 = 0;
uint16_t tempw, src16;
uint8_t src, dst;
int8_t temps;
fetch_ea_16(fetchdat);
dst = geteab(); if (cpu_state.abrt) return 1;
@@ -130,32 +131,24 @@ static int opF6_a16(uint32_t fetchdat)
PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
break;
case 0x38: /*IDIV AL,b*/
if (dst == 0) {
x86_int(0); /* Divide by zero. */
return 1;
}
tempsrc = (int16_t) AX;
tempdst = (int8_t) dst;
tempws = tempsrc / tempdst;
if ((tempws > 127) || (tempws < -128)) {
x86_int(0);
return 1;
}
tempws = (int8_t) tempws;
tempws2 = (int8_t) (tempsrc % tempdst);
AH = (uint8_t) tempws2;
AL = (uint8_t) tempws;
if (!cpu_iscyrix) {
flags_rebuild();
flags|=0x8D5; /*Not a Cyrix*/
}
tempws = (int)(int16_t)AX;
if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
temps = tempws2 & 0xff;
if (dst && ((int)temps == tempws2))
{
AH = (tempws % (int)((int8_t)dst)) & 0xff;
AL = tempws2 & 0xff;
if (!cpu_iscyrix)
{
flags_rebuild();
flags|=0x8D5; /*Not a Cyrix*/
}
}
else
{
x86_int(0);
return 1;
}
CLOCK_CYCLES(19);
PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
break;
@@ -168,9 +161,10 @@ static int opF6_a16(uint32_t fetchdat)
}
static int opF6_a32(uint32_t fetchdat)
{
int tempsrc, tempdst, tempws, tempws2 = 0;
int tempws, tempws2 = 0;
uint16_t tempw, src16;
uint8_t src, dst;
int8_t temps;
fetch_ea_32(fetchdat);
dst = geteab(); if (cpu_state.abrt) return 1;
@@ -234,32 +228,24 @@ static int opF6_a32(uint32_t fetchdat)
PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
break;
case 0x38: /*IDIV AL,b*/
if (dst == 0) {
x86_int(0); /* Divide by zero. */
return 1;
}
tempsrc = (int16_t) AX;
tempdst = (int8_t) dst;
tempws = tempsrc / tempdst;
if ((tempws > 127) || (tempws < -128)) {
x86_int(0);
return 1;
}
tempws = (int8_t) tempws;
tempws2 = (int8_t) (tempsrc % tempdst);
AH = (uint8_t) tempws2;
AL = (uint8_t) tempws;
if (!cpu_iscyrix) {
flags_rebuild();
flags|=0x8D5; /*Not a Cyrix*/
}
tempws = (int)(int16_t)AX;
if (dst != 0) tempws2 = tempws / (int)((int8_t)dst);
temps = tempws2 & 0xff;
if (dst && ((int)temps == tempws2))
{
AH = (tempws % (int)((int8_t)dst)) & 0xff;
AL = tempws2 & 0xff;
if (!cpu_iscyrix)
{
flags_rebuild();
flags|=0x8D5; /*Not a Cyrix*/
}
}
else
{
x86_int(0);
return 1;
}
CLOCK_CYCLES(19);
PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
break;
@@ -276,7 +262,8 @@ static int opF6_a32(uint32_t fetchdat)
static int opF7_w_a16(uint32_t fetchdat)
{
uint32_t templ, templ2;
int32_t tempsrc, tempdst, tempws, tempws2 = 0;
int tempws, tempws2 = 0;
int16_t temps16;
uint16_t src, dst;
fetch_ea_16(fetchdat);
@@ -339,32 +326,21 @@ static int opF7_w_a16(uint32_t fetchdat)
CLOCK_CYCLES(is486 ? 24 : 22);
PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
break;
case 0x38: /*IDIV DX:AX,w*/
if (dst == 0) {
x86_int(0); /* Divide by zero. */
return 1;
}
templ = (uint32_t) DX;
templ = (templ << 16) | AX;
tempsrc = (int32_t) templ;
tempdst = (int16_t) dst;
tempws = tempsrc / tempdst;
if ((tempws > 32767) || (tempws < -32768)) {
x86_int(0);
return 1;
}
tempws = (int16_t) tempws;
tempws2 = (int16_t) (tempsrc % tempdst);
DX = (uint16_t) tempws2;
AX = (uint16_t) tempws;
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
case 0x38: /*IDIV AX,w*/
tempws = (int)((DX << 16)|AX);
if (dst) tempws2 = tempws / (int)((int16_t)dst);
temps16 = tempws2 & 0xffff;
if ((dst != 0) && ((int)temps16 == tempws2))
{
DX = tempws % (int)((int16_t)dst);
AX = tempws2 & 0xffff;
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
}
else
{
x86_int(0);
return 1;
}
CLOCK_CYCLES(27);
PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0);
break;
@@ -378,7 +354,8 @@ static int opF7_w_a16(uint32_t fetchdat)
static int opF7_w_a32(uint32_t fetchdat)
{
uint32_t templ, templ2;
int tempsrc, tempdst, tempws, tempws2 = 0;
int tempws, tempws2 = 0;
int16_t temps16;
uint16_t src, dst;
fetch_ea_32(fetchdat);
@@ -441,32 +418,21 @@ static int opF7_w_a32(uint32_t fetchdat)
CLOCK_CYCLES(is486 ? 24 : 22);
PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
break;
case 0x38: /*IDIV DX:AX,w*/
if (dst == 0) {
x86_int(0); /* Divide by zero. */
return 1;
}
templ = (uint32_t) DX;
templ = (templ << 16) | AX;
tempsrc = (int32_t) templ;
tempdst = (int16_t) dst;
tempws = tempsrc / tempdst;
if ((tempws > 32767) || (tempws < -32768)) {
x86_int(0);
return 1;
}
tempws = (int16_t) tempws;
tempws2 = (int16_t) (tempsrc % tempdst);
DX = (uint16_t) tempws2;
AX = (uint16_t) tempws;
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
case 0x38: /*IDIV AX,w*/
tempws = (int)((DX << 16)|AX);
if (dst) tempws2 = tempws / (int)((int16_t)dst);
temps16 = tempws2 & 0xffff;
if ((dst != 0) && ((int)temps16 == tempws2))
{
DX = tempws % (int)((int16_t)dst);
AX = tempws2 & 0xffff;
if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/
}
else
{
x86_int(0);
return 1;
}
CLOCK_CYCLES(27);
PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1);
break;

View File

@@ -8,7 +8,7 @@
*
* Main emulator module where most things are controlled.
*
* Version: @(#)pc.c 1.0.50 2017/12/15
* Version: @(#)pc.c 1.0.51 2017/12/16
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -196,8 +196,8 @@ pclog_ex(const char *fmt, va_list ap)
} else {
if (seen) {
fprintf(stdlog, "*** %d repeats ***\n", seen);
seen = 0;
}
seen = 0;
strcpy(buff, temp);
fprintf(stdlog, temp, ap);
}

View File

@@ -10,7 +10,7 @@
* NCR and later Symbios and LSI. This controller was designed
* for the PCI bus.
*
* Version: @(#)scsi_ncr53c810.c 1.0.1 2017/12/15
* Version: @(#)scsi_ncr53c810.c 1.0.2 2017/12/16
*
* Authors: Paul Brook (QEMU)
* Artyom Tarasenko (QEMU)
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include "../86box.h"
#include "../io.h"
#include "../dma.h"
@@ -208,7 +209,7 @@ typedef struct {
* 1 if a Wait Reselect instruction has been issued.
* 2 if processing DMA from lsi_execute_script.
* 3 if a DMA operation is in progress. */
int waiting;
volatile uint8_t waiting, sstop;
uint8_t current_lun;
uint8_t select_id;
@@ -261,7 +262,8 @@ typedef struct {
uint8_t stime0;
uint8_t respid0;
uint8_t respid1;
uint32_t scratch[4]; /* SCRATCHA-SCRATCHR */
uint32_t scratch;
uint32_t scratch2; /* SCRATCHA-SCRATCHD */
uint8_t sbr;
uint8_t chip_rev;
int last_level;
@@ -273,16 +275,33 @@ typedef struct {
/* Script ram is stored as 32-bit words in host byteorder. */
uint8_t script_ram[8192];
uint8_t sstop;
uint32_t prefetch;
uint8_t prefetch_used;
uint8_t regop;
uint32_t adder;
uint8_t ncr_to_ncr;
} LSIState;
static volatile
thread_t *poll_tid;
static volatile
int busy;
static volatile
event_t *evt;
static volatile
event_t *wait_evt;
static volatile
event_t *wake_poll_thread;
static volatile
event_t *thread_started;
static volatile
event_t *waiting_state;
static volatile
LSIState *lsi_dev;
#ifdef ENABLE_NCR53C810_LOG
int ncr53c810_do_log = ENABLE_NCR53C810_LOG;
#endif
@@ -313,9 +332,6 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val);
static void lsi_execute_script(LSIState *s);
static void lsi_reselect(LSIState *s, lsi_request *p);
static void lsi_command_complete(void *priv, uint32_t status);
#if 0
static void lsi_transfer_data(void *priv, uint32_t len, uint8_t id);
#endif
static inline int32_t sextract32(uint32_t value, int start, int length)
{
@@ -350,7 +366,7 @@ static void lsi_soft_reset(LSIState *s)
s->dnad = 0;
s->dbc = 0;
s->temp = 0;
memset(s->scratch, 0, sizeof(s->scratch));
s->scratch = s->scratch2 = 0;
s->istat0 = 0;
s->istat1 = 0;
s->dcmd = 0x40;
@@ -393,8 +409,7 @@ static void lsi_soft_reset(LSIState *s)
s->last_level = 0;
s->gpreg0 = 0;
s->sstop = 1;
s->prefetch = 0;
s->prefetch_used = 0;
s->ncr_to_ncr = 0;
}
@@ -406,10 +421,28 @@ static void lsi_read(LSIState *s, uint32_t addr, uint8_t *buf, uint32_t len)
if (s->dmode & LSI_DMODE_SIOM) {
ncr53c810_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr);
if ((addr & 0xFF00) == s->PCIBase) {
s->ncr_to_ncr = 1;
for (i = 0; i < len; i++)
buf[i] = lsi_reg_readb(s, addr & 0xFF);
s->ncr_to_ncr = 0;
return;
}
for (i = 0; i < len; i++)
buf[i] = inb((uint16_t) (addr + i));
} else {
ncr53c810_log("NCR 810: Reading from memory address %08X\n", addr);
if ((addr & 0xFFFFFF00) == s->MMIOBase) {
s->ncr_to_ncr = 1;
for (i = 0; i < len; i++)
buf[i] = lsi_reg_readb(s, addr & 0xFF);
s->ncr_to_ncr = 0;
return;
}
DMAPageRead(addr, buf, len);
}
}
@@ -422,10 +455,28 @@ static void lsi_write(LSIState *s, uint32_t addr, uint8_t *buf, uint32_t len)
if (s->dmode & LSI_DMODE_DIOM) {
ncr53c810_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr);
if ((addr & 0xFF00) == s->PCIBase) {
s->ncr_to_ncr = 1;
for (i = 0; i < len; i++)
lsi_reg_writeb(s, addr & 0xFF, buf[i]);
s->ncr_to_ncr = 0;
return;
}
for (i = 0; i < len; i++)
outb((uint16_t) (addr + i), buf[i]);
} else {
ncr53c810_log("NCR 810: Writing to memory address %08X\n", addr);
if ((addr & 0xFFFFFF00) == s->MMIOBase) {
s->ncr_to_ncr = 1;
for (i = 0; i < len; i++)
lsi_reg_writeb(s, addr & 0xFF, buf[i]);
s->ncr_to_ncr = 0;
return;
}
DMAPageWrite(addr, buf, len);
}
}
@@ -543,19 +594,8 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
}
/* Resume SCRIPTS execution after a DMA operation. */
static void lsi_resume_script(LSIState *s)
{
ncr53c810_log("lsi_resume_script()\n");
if (s->waiting != 2) {
s->waiting = 0;
lsi_execute_script(s);
} else {
s->waiting = 0;
}
}
static void lsi_disconnect(LSIState *s)
static void
lsi_disconnect(LSIState *s)
{
s->scntl1 &= ~LSI_SCNTL1_CON;
s->sstat1 &= ~PHASE_MASK;
@@ -563,14 +603,18 @@ static void lsi_disconnect(LSIState *s)
s->sstat1 |= 0x07;
}
static void lsi_bad_selection(LSIState *s, uint32_t id)
static void
lsi_bad_selection(LSIState *s, uint32_t id)
{
DPRINTF("Selected absent target %d\n", id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
}
static void lsi_do_dma(LSIState *s, int out, uint8_t id)
static void
lsi_do_dma(LSIState *s, int out, uint8_t id)
{
uint32_t addr, count, tdbc;
@@ -625,12 +669,14 @@ static void lsi_do_dma(LSIState *s, int out, uint8_t id)
lsi_command_complete(s, SCSIStatus);
} else {
DPRINTF("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, s->current_lun, s->last_command);
lsi_resume_script(s);
s->sstop = 0;
}
}
/* Queue a byte for a MSG IN phase. */
static void lsi_add_msg_byte(LSIState *s, uint8_t data)
static void
lsi_add_msg_byte(LSIState *s, uint8_t data)
{
if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
BADF("MSG IN data too long\n");
@@ -640,8 +686,33 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data)
}
}
static void
lsi_busy(uint8_t set)
{
if (busy == !!set)
return;
busy = !!set;
ncr53c810_log("NCR 810: Busy is now %s...\n", busy ? "ON" : "OFF");
if (!set) {
ncr53c810_log("NCR 810: Setting thread wake event...\n", busy ? "ON" : "OFF");
thread_set_event((event_t *) wake_poll_thread);
}
}
static void
lsi_set_wake_event(void)
{
ncr53c810_log("NCR 810: Setting wait event arrived...\n");
thread_set_event((event_t *)waiting_state);
}
/* Perform reselection to continue a command. */
static void lsi_reselect(LSIState *s, lsi_request *p)
static void
lsi_reselect(LSIState *s, lsi_request *p)
{
int id;
@@ -671,6 +742,9 @@ static void lsi_reselect(LSIState *s, lsi_request *p)
if (lsi_irq_on_rsl(s)) {
lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
}
s->sstop = s->waiting = 0;
lsi_set_wake_event();
}
@@ -726,7 +800,7 @@ static void lsi_command_complete(void *priv, uint32_t status)
s->hba_private = NULL;
lsi_request_free(s, s->current);
}
lsi_resume_script(s);
s->sstop = 0;
}
static void lsi_do_command(LSIState *s, uint8_t id)
@@ -1004,7 +1078,8 @@ static void lsi_wait_reselect(LSIState *s)
}
}
static void lsi_execute_script(LSIState *s)
static void
lsi_process_script(LSIState *s)
{
uint32_t insn;
uint32_t addr;
@@ -1012,16 +1087,14 @@ static void lsi_execute_script(LSIState *s)
int insn_processed = 0;
uint32_t id;
/* s->istat1 |= LSI_ISTAT1_SRUN; */
s->sstop = 0;
again:
insn_processed++;
insn = read_dword(s, s->dsp);
if (!insn) {
/* If we receive an empty opcode increment the DSP by 4 bytes
instead of 8 and execute the next opcode at that location */
s->dsp += 4;
goto again;
return; /* The thread will take care of resuming execution. */
}
addr = read_dword(s, s->dsp + 4);
DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
@@ -1266,7 +1339,9 @@ again:
switch (opcode) {
case 5: /* From SFBR */
case 7: /* Read-modify-write */
s->ncr_to_ncr = 1;
lsi_reg_writeb(s, reg, op0);
s->ncr_to_ncr = 0;
break;
case 6: /* To SFBR */
s->sfbr = op0;
@@ -1410,9 +1485,10 @@ again:
if (s->dcntl & LSI_DCNTL_SSM) {
ncr53c810_log("NCR 810: SCRIPTS: Single-step mode\n");
lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
s->sstop = 1;
} else {
ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n");
goto again;
return;
}
} else {
if (s->sstop)
@@ -1424,7 +1500,102 @@ again:
DPRINTF("SCRIPTS execution stopped\n");
}
static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
static uint8_t
lsi_is_busy(void)
{
return(!!busy);
}
void
lsi_wait_for_poll(void)
{
if (lsi_is_busy()) {
ncr53c810_log("NCR 810: Waiting for thread wake event...\n");
thread_wait_event((event_t *) wake_poll_thread, -1);
}
ncr53c810_log("NCR 810: Thread wake event arrived...\n");
thread_reset_event((event_t *) wake_poll_thread);
}
void
lsi_wait_for_resume(void)
{
if (lsi_dev && (lsi_dev->waiting == 1)) {
ncr53c810_log("NCR 810: Waiting for thread resume event...\n");
thread_wait_event((event_t *) waiting_state, -1);
}
ncr53c810_log("NCR 810: Thread resume event arrived...\n");
thread_reset_event((event_t *) waiting_state);
}
static void
lsi_script_thread(void *priv)
{
LSIState *dev = (LSIState *) lsi_dev;
thread_set_event((event_t *) thread_started);
ncr53c810_log("Polling thread started\n");
while (lsi_dev) {
scsi_mutex_wait(1);
if (!dev->sstop) {
lsi_wait_for_poll();
if (dev->waiting) {
/* Wait for event followed by a clear of the waiting state
if waiting for reselect. */
lsi_wait_for_resume();
thread_wait_event((event_t *) wait_evt, dev->waiting);
}
if (!dev->waiting)
lsi_process_script(dev);
} else
thread_wait_event((event_t *) wait_evt, 10);
scsi_mutex_wait(0);
}
ncr53c810_log("NCR 810: Callback: polling stopped.\n");
}
static void
lsi_thread_start(LSIState *dev)
{
if (!poll_tid) {
poll_tid = thread_create(lsi_script_thread, dev);
}
}
static void
lsi_set_wait_event(void)
{
ncr53c810_log("NCR 810: Setting wait event arrived...\n");
thread_set_event((event_t *)wait_evt);
}
static void
lsi_execute_script(LSIState *s)
{
lsi_busy(1);
s->sstop = s->waiting = 0;
lsi_set_wait_event();
lsi_busy(0);
}
static void
lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
{
uint8_t tmp = 0;
@@ -1439,11 +1610,12 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
// #ifdef DEBUG_LSI_REG
DPRINTF("Write reg %02x = %02x\n", offset, val);
// #endif
if (!s->ncr_to_ncr)
lsi_busy(1);
s->regop = 1;
#ifdef DEBUG_LSI_REG
DPRINTF("Write reg %02x = %02x\n", offset, val);
#endif
switch (offset) {
case 0x00: /* SCNTL0 */
@@ -1516,10 +1688,10 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
break;
case 0x0a: case 0x0b:
/* Openserver writes to these readonly registers on startup */
return;
break;
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
/* Linux writes to these readonly registers on startup. */
return;
break;
CASE_SET_REG32(dsa, 0x10)
case 0x14: /* ISTAT0 */
ncr53c810_log("ISTAT0 write: %02X\n", val);
@@ -1537,7 +1709,7 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
DPRINTF("Woken by SIGP\n");
s->waiting = 0;
s->dsp = s->dnad;
lsi_execute_script(s);
lsi_set_wake_event();
}
if ((val & LSI_ISTAT0_SRST) && !(tmp & LSI_ISTAT0_SRST)) {
lsi_soft_reset(s);
@@ -1598,7 +1770,7 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
}
break;
CASE_SET_REG32(dsps, 0x30)
CASE_SET_REG32(scratch[0], 0x34)
CASE_SET_REG32(scratch, 0x34)
case 0x38: /* DMODE */
s->dmode = val;
break;
@@ -1658,19 +1830,16 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
}
s->stest3 = val;
break;
case 0x54:
break;
case 0x54:
break;
CASE_SET_REG32(scratch2, 0x5c)
default:
if (offset >= 0x5c && offset < 0x60) {
int n;
int shift;
n = (offset - 0x58) >> 2;
shift = (offset & 3) * 8;
s->scratch[n] = deposit32(s->scratch[n], shift, 8, val);
} else {
BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
}
BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
}
if (!s->ncr_to_ncr)
lsi_busy(0);
#undef CASE_SET_REG24
#undef CASE_SET_REG32
}
@@ -1678,50 +1847,62 @@ static void lsi_reg_writeb(LSIState *s, uint32_t offset, uint8_t val)
static uint8_t lsi_reg_readb(LSIState *s, uint32_t offset)
{
uint8_t tmp;
uint8_t ret = 0;
#define CASE_GET_REG24(name, addr) \
case addr: return s->name & 0xff; \
case addr + 1: return (s->name >> 8) & 0xff; \
case addr + 2: return (s->name >> 16) & 0xff;
case addr: ret = s->name & 0xff; break; \
case addr + 1: ret = (s->name >> 8) & 0xff; break; \
case addr + 2: ret = (s->name >> 16) & 0xff; break;
#define CASE_GET_REG32(name, addr) \
case addr: return s->name & 0xff; \
case addr + 1: return (s->name >> 8) & 0xff; \
case addr + 2: return (s->name >> 16) & 0xff; \
case addr + 3: return (s->name >> 24) & 0xff;
case addr: ret = s->name & 0xff; break; \
case addr + 1: ret = (s->name >> 8) & 0xff; break; \
case addr + 2: ret = (s->name >> 16) & 0xff; break; \
case addr + 3: ret = (s->name >> 24) & 0xff; break;
s->regop = 1;
if (!s->ncr_to_ncr)
lsi_busy(1);
switch (offset) {
case 0x00: /* SCNTL0 */
ncr53c810_log("NCR 810: Read SCNTL0 %02X\n", s->scntl0);
return s->scntl0;
ret = s->scntl0;
break;
case 0x01: /* SCNTL1 */
ncr53c810_log("NCR 810: Read SCNTL1 %02X\n", s->scntl1);
return s->scntl1;
ret = s->scntl1;
break;
case 0x02: /* SCNTL2 */
ncr53c810_log("NCR 810: Read SCNTL2 %02X\n", s->scntl2);
return s->scntl2;
ret = s->scntl2;
break;
case 0x03: /* SCNTL3 */
ncr53c810_log("NCR 810: Read SCNTL3 %02X\n", s->scntl3);
return s->scntl3;
ret = s->scntl3;
break;
case 0x04: /* SCID */
ncr53c810_log("NCR 810: Read SCID %02X\n", s->scid);
return s->scid;
ret = s->scid;
break;
case 0x05: /* SXFER */
ncr53c810_log("NCR 810: Read SXFER %02X\n", s->sxfer);
return s->sxfer;
ret = s->sxfer;
break;
case 0x06: /* SDID */
ncr53c810_log("NCR 810: Read SDID %02X\n", s->sdid);
return s->sdid;
ret = s->sdid;
break;
case 0x07: /* GPREG0 */
ncr53c810_log("NCR 810: Read GPREG0 %02X\n", s->gpreg0 & 3);
return s->gpreg0 & 3;
ret = s->gpreg0 & 3;
break;
case 0x08: /* Revision ID */
ncr53c810_log("NCR 810: Read REVID 00\n");
return 0x00;
ret = 0x00;
break;
case 0xa: /* SSID */
ncr53c810_log("NCR 810: Read SSID %02X\n", s->ssid);
return s->ssid;
ret = s->ssid;
break;
case 0xb: /* SBCL */
/* ??? This is not correct. However it's (hopefully) only
used for diagnostics, so should be ok. */
@@ -1735,42 +1916,53 @@ static uint8_t lsi_reg_readb(LSIState *s, uint32_t offset)
Bit 0 = I/O (SI_O/ status) */
tmp = (s->sstat1 & 7);
ncr53c810_log("NCR 810: Read SBCL %02X\n", tmp);
return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */
ret = tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */
break;
case 0xc: /* DSTAT */
tmp = s->dstat | LSI_DSTAT_DFE;
if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
s->dstat = 0;
lsi_update_irq(s);
ncr53c810_log("NCR 810: Read DSTAT %02X\n", tmp);
return tmp;
ret = tmp;
break;
case 0x0d: /* SSTAT0 */
ncr53c810_log("NCR 810: Read SSTAT0 %02X\n", s->sstat0);
return s->sstat0;
ret = s->sstat0;
break;
case 0x0e: /* SSTAT1 */
ncr53c810_log("NCR 810: Read SSTAT1 %02X\n", s->sstat1);
return s->sstat1;
ret = s->sstat1;
break;
case 0x0f: /* SSTAT2 */
ncr53c810_log("NCR 810: Read SSTAT2 %02X\n", s->scntl1 & LSI_SCNTL1_CON ? 0 : 2);
return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
ret = s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
break;
CASE_GET_REG32(dsa, 0x10)
case 0x14: /* ISTAT0 */
ncr53c810_log("NCR 810: Read ISTAT0 %02X\n", s->istat0);
return s->istat0;
ret = s->istat0;
break;
case 0x15: /* ISTAT1 */
ncr53c810_log("NCR 810: Read ISTAT1 %02X\n", s->istat1);
return s->istat1;
ret = s->istat1;
break;
case 0x16: /* MBOX0 */
ncr53c810_log("NCR 810: Read MBOX0 %02X\n", s->mbox0);
return s->mbox0;
ret = s->mbox0;
break;
case 0x17: /* MBOX1 */
ncr53c810_log("NCR 810: Read MBOX1 %02X\n", s->mbox1);
return s->mbox1;
ret = s->mbox1;
break;
case 0x18: /* CTEST0 */
ncr53c810_log("NCR 810: Read CTEST0 FF\n");
return 0xff;
ret = 0xff;
break;
case 0x19: /* CTEST1 */
ncr53c810_log("NCR 810: Read CTEST1 F0\n");
return 0xf0; /* dma fifo empty */
ret = 0xf0; /* dma fifo empty */
break;
case 0x1a: /* CTEST2 */
tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
if (s->istat0 & LSI_ISTAT0_SIGP) {
@@ -1778,119 +1970,146 @@ static uint8_t lsi_reg_readb(LSIState *s, uint32_t offset)
tmp |= LSI_CTEST2_SIGP;
}
ncr53c810_log("NCR 810: Read CTEST2 %02X\n", tmp);
return tmp;
ret = tmp;
break;
case 0x1b: /* CTEST3 */
ncr53c810_log("NCR 810: Read CTEST3 %02X\n", (s->ctest3 & (0x08 | 0x02 | 0x01)) | s->chip_rev);
return (s->ctest3 & (0x08 | 0x02 | 0x01)) | s->chip_rev;
ret = (s->ctest3 & (0x08 | 0x02 | 0x01)) | s->chip_rev;
break;
CASE_GET_REG32(temp, 0x1c)
case 0x20: /* DFIFO */
ncr53c810_log("NCR 810: Read DFIFO 00\n");
return 0;
ret = 0;
break;
case 0x21: /* CTEST4 */
ncr53c810_log("NCR 810: Read CTEST4 %02X\n", s->ctest4);
return s->ctest4;
ret = s->ctest4;
break;
case 0x22: /* CTEST5 */
ncr53c810_log("NCR 810: Read CTEST5 %02X\n", s->ctest5);
return s->ctest5;
ret = s->ctest5;
break;
case 0x23: /* CTEST6 */
ncr53c810_log("NCR 810: Read CTEST6 00\n");
return 0;
ret = 0;
break;
CASE_GET_REG24(dbc, 0x24)
case 0x27: /* DCMD */
ncr53c810_log("NCR 810: Read DCMD %02X\n", s->dcmd);
return s->dcmd;
ret = s->dcmd;
break;
CASE_GET_REG32(dnad, 0x28)
CASE_GET_REG32(dsp, 0x2c)
CASE_GET_REG32(dsps, 0x30)
CASE_GET_REG32(scratch[0], 0x34)
CASE_GET_REG32(scratch, 0x34)
case 0x38: /* DMODE */
ncr53c810_log("NCR 810: Read DMODE %02X\n", s->dmode);
return s->dmode;
ret = s->dmode;
break;
case 0x39: /* DIEN */
ncr53c810_log("NCR 810: Read DIEN %02X\n", s->dien);
return s->dien;
ret = s->dien;
break;
case 0x3a: /* SBR */
ncr53c810_log("NCR 810: Read SBR %02X\n", s->sbr);
return s->sbr;
ret = s->sbr;
break;
case 0x3b: /* DCNTL */
ncr53c810_log("NCR 810: Read DCNTL %02X\n", s->dcntl);
return s->dcntl;
ret = s->dcntl;
break;
/* ADDER Output (Debug of relative jump address) */
CASE_GET_REG32(adder, 0x3c)
case 0x40: /* SIEN0 */
ncr53c810_log("NCR 810: Read SIEN0 %02X\n", s->sien0);
return s->sien0;
ret = s->sien0;
break;
case 0x41: /* SIEN1 */
ncr53c810_log("NCR 810: Read SIEN1 %02X\n", s->sien1);
return s->sien1;
ret = s->sien1;
break;
case 0x42: /* SIST0 */
tmp = s->sist0;
s->sist0 = 0;
lsi_update_irq(s);
ncr53c810_log("NCR 810: Read SIST0 %02X\n", tmp);
return tmp;
ret = tmp;
break;
case 0x43: /* SIST1 */
tmp = s->sist1;
s->sist1 = 0;
lsi_update_irq(s);
ncr53c810_log("NCR 810: Read SIST1 %02X\n", tmp);
return tmp;
ret = tmp;
break;
case 0x46: /* MACNTL */
ncr53c810_log("NCR 810: Read MACNTL 4F\n");
return 0x4f;
ret = 0x4f;
break;
case 0x47: /* GPCNTL0 */
ncr53c810_log("NCR 810: Read GPCNTL0 0F\n");
return 0x0f;
ret = 0x0f;
break;
case 0x48: /* STIME0 */
ncr53c810_log("NCR 810: Read STIME0 %02X\n", s->stime0);
return s->stime0;
ret = s->stime0;
break;
case 0x4a: /* RESPID0 */
ncr53c810_log("NCR 810: Read RESPID0 %02X\n", s->respid0);
return s->respid0;
ret = s->respid0;
break;
case 0x4b: /* RESPID1 */
ncr53c810_log("NCR 810: Read RESPID1 %02X\n", s->respid1);
return s->respid1;
ret = s->respid1;
break;
case 0x4d: /* STEST1 */
ncr53c810_log("NCR 810: Read STEST1 %02X\n", s->stest1);
return s->stest1;
ret = s->stest1;
break;
case 0x4e: /* STEST2 */
ncr53c810_log("NCR 810: Read STEST2 %02X\n", s->stest2);
return s->stest2;
ret = s->stest2;
break;
case 0x4f: /* STEST3 */
ncr53c810_log("NCR 810: Read STEST3 %02X\n", s->stest3);
return s->stest3;
ret = s->stest3;
break;
case 0x50: /* SIDL */
/* This is needed by the linux drivers. We currently only update it
during the MSG IN phase. */
ncr53c810_log("NCR 810: Read SIDL %02X\n", s->sidl);
return s->sidl;
ret = s->sidl;
break;
case 0x52: /* STEST4 */
ncr53c810_log("NCR 810: Read STEST4 E0\n");
return 0xe0;
ret = 0xe0;
break;
case 0x58: /* SBDL */
/* Some drivers peek at the data bus during the MSG IN phase. */
if ((s->sstat1 & PHASE_MASK) == PHASE_MI) {
ncr53c810_log("NCR 810: Read SBDL %02X\n", s->msg[0]);
return s->msg[0];
ret = s->msg[0];
}
ncr53c810_log("NCR 810: Read SBDL 00\n");
return 0;
ret = 0;
break;
case 0x59: /* SBDL high */
ncr53c810_log("NCR 810: Read SBDLH 00\n");
return 0;
ret = 0;
break;
CASE_GET_REG32(scratch2, 0x5c)
default:
BADF("readb 0x%x\n", offset);
ret = 0;
break;
}
if (offset >= 0x5c && offset < 0x60) {
int n;
int shift;
n = (offset - 0x58) >> 2;
shift = (offset & 3) * 8;
ncr53c810_log("NCR 810: Read SCRATCH%i %02X\n", offset & 3, (s->scratch[n] >> shift) & 0xff);
return (s->scratch[n] >> shift) & 0xff;
}
BADF("readb 0x%x\n", offset);
return 0;
#undef CASE_GET_REG24
#undef CASE_GET_REG32
if (!s->ncr_to_ncr)
lsi_busy(0);
return ret;
}
static uint8_t lsi_io_readb(uint16_t addr, void *p)
@@ -2232,6 +2451,21 @@ ncr53c810_init(device_t *info)
lsi_soft_reset(s);
lsi_dev = s;
scsi_mutex(1);
wake_poll_thread = thread_create_event();
thread_started = thread_create_event();
waiting_state = thread_create_event();
/* Create a waitable event. */
evt = thread_create_event();
wait_evt = thread_create_event();
lsi_thread_start(s);
thread_wait_event((event_t *) thread_started, -1);
return(s);
}
@@ -2239,11 +2473,52 @@ ncr53c810_init(device_t *info)
static void
ncr53c810_close(void *priv)
{
LSIState *s = (LSIState *)priv;
LSIState *dev = (LSIState *)priv;
if (s) {
free(s);
s = NULL;
if (dev) {
lsi_dev = NULL;
/* Tell the thread to terminate. */
if (poll_tid != NULL) {
lsi_busy(0);
/* Wait for the end event. */
thread_wait((event_t *) poll_tid, -1);
poll_tid = NULL;
}
dev->sstop = 1;
if (wait_evt) {
thread_destroy_event((event_t *) evt);
evt = NULL;
}
if (evt) {
thread_destroy_event((event_t *) evt);
evt = NULL;
}
if (waiting_state) {
thread_destroy_event((event_t *) waiting_state);
thread_started = NULL;
}
if (thread_started) {
thread_destroy_event((event_t *) thread_started);
thread_started = NULL;
}
if (wake_poll_thread) {
thread_destroy_event((event_t *) wake_poll_thread);
wake_poll_thread = NULL;
}
scsi_mutex(0);
free(dev);
dev = NULL;
}
}