diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 272a4b21e..9c887db29 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -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; } diff --git a/src/cpu/codegen.h b/src/cpu/codegen.h index 1c760d696..99703e370 100644 --- a/src/cpu/codegen.h +++ b/src/cpu/codegen.h @@ -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; diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index e3cb65251..7448007fb 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -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; diff --git a/src/pc.c b/src/pc.c index 7392eb0ae..35f30e11e 100644 --- a/src/pc.c +++ b/src/pc.c @@ -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, * Miran Grca, @@ -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); } diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c810.c index e75e469f1..493e169b1 100644 --- a/src/scsi/scsi_ncr53c810.c +++ b/src/scsi/scsi_ncr53c810.c @@ -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 #include #include +#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; } }