📄 lsi53c895a.c
字号:
DPRINTF("Selected target %d%s\n", id, insn & (1 << 3) ? " ATN" : ""); /* ??? Linux drivers compain when this is set. Maybe it only applies in low-level mode (unimplemented). lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ s->current_dev = s->scsi_dev[id]; s->current_tag = id << 8; s->scntl1 |= LSI_SCNTL1_CON; if (insn & (1 << 3)) { s->socl |= LSI_SOCL_ATN; } lsi_set_phase(s, PHASE_MO); break; case 1: /* Disconnect */ DPRINTF("Wait Disconect\n"); s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ lsi_wait_reselect(s); break; case 3: /* Set */ DPRINTF("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", insn & (1 << 10) ? " CC" : ""); if (insn & (1 << 3)) { s->socl |= LSI_SOCL_ATN; lsi_set_phase(s, PHASE_MO); } if (insn & (1 << 9)) { BADF("Target mode not implemented\n"); exit(1); } if (insn & (1 << 10)) s->carry = 1; break; case 4: /* Clear */ DPRINTF("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", insn & (1 << 10) ? " CC" : ""); if (insn & (1 << 3)) { s->socl &= ~LSI_SOCL_ATN; } if (insn & (1 << 10)) s->carry = 0; break; } } else { uint8_t op0; uint8_t op1; uint8_t data8; int reg; int operator;#ifdef DEBUG_LSI static const char *opcode_names[3] = {"Write", "Read", "Read-Modify-Write"}; static const char *operator_names[8] = {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};#endif reg = ((insn >> 16) & 0x7f) | (insn & 0x80); data8 = (insn >> 8) & 0xff; opcode = (insn >> 27) & 7; operator = (insn >> 24) & 7; DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n", opcode_names[opcode - 5], reg, operator_names[operator], data8, s->sfbr, (insn & (1 << 23)) ? " SFBR" : ""); op0 = op1 = 0; switch (opcode) { case 5: /* From SFBR */ op0 = s->sfbr; op1 = data8; break; case 6: /* To SFBR */ if (operator) op0 = lsi_reg_readb(s, reg); op1 = data8; break; case 7: /* Read-modify-write */ if (operator) op0 = lsi_reg_readb(s, reg); if (insn & (1 << 23)) { op1 = s->sfbr; } else { op1 = data8; } break; } switch (operator) { case 0: /* move */ op0 = op1; break; case 1: /* Shift left */ op1 = op0 >> 7; op0 = (op0 << 1) | s->carry; s->carry = op1; break; case 2: /* OR */ op0 |= op1; break; case 3: /* XOR */ op0 |= op1; break; case 4: /* AND */ op0 &= op1; break; case 5: /* SHR */ op1 = op0 & 1; op0 = (op0 >> 1) | (s->carry << 7); break; case 6: /* ADD */ op0 += op1; s->carry = op0 < op1; break; case 7: /* ADC */ op0 += op1 + s->carry; if (s->carry) s->carry = op0 <= op1; else s->carry = op0 < op1; break; } switch (opcode) { case 5: /* From SFBR */ case 7: /* Read-modify-write */ lsi_reg_writeb(s, reg, op0); break; case 6: /* To SFBR */ s->sfbr = op0; break; } } break; case 2: /* Transfer Control. */ { int cond; int jmp; if ((insn & 0x002e0000) == 0) { DPRINTF("NOP\n"); break; } if (s->sist1 & LSI_SIST1_STO) { DPRINTF("Delayed select timeout\n"); lsi_stop_script(s); break; } cond = jmp = (insn & (1 << 19)) != 0; if (cond == jmp && (insn & (1 << 21))) { DPRINTF("Compare carry %d\n", s->carry == jmp); cond = s->carry != 0; } if (cond == jmp && (insn & (1 << 17))) { DPRINTF("Compare phase %d %c= %d\n", (s->sstat1 & PHASE_MASK), jmp ? '=' : '!', ((insn >> 24) & 7)); cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); } if (cond == jmp && (insn & (1 << 18))) { uint8_t mask; mask = (~insn >> 8) & 0xff; DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n", s->sfbr, mask, jmp ? '=' : '!', insn & mask); cond = (s->sfbr & mask) == (insn & mask); } if (cond == jmp) { if (insn & (1 << 23)) { /* Relative address. */ addr = s->dsp + sxt24(addr); } switch ((insn >> 27) & 7) { case 0: /* Jump */ DPRINTF("Jump to 0x%08x\n", addr); s->dsp = addr; break; case 1: /* Call */ DPRINTF("Call 0x%08x\n", addr); s->temp = s->dsp; s->dsp = addr; break; case 2: /* Return */ DPRINTF("Return to 0x%08x\n", s->temp); s->dsp = s->temp; break; case 3: /* Interrupt */ DPRINTF("Interrupt 0x%08x\n", s->dsps); if ((insn & (1 << 20)) != 0) { s->istat0 |= LSI_ISTAT0_INTF; lsi_update_irq(s); } else { lsi_script_dma_interrupt(s, LSI_DSTAT_SIR); } break; default: DPRINTF("Illegal transfer control\n"); lsi_script_dma_interrupt(s, LSI_DSTAT_IID); break; } } else { DPRINTF("Control condition failed\n"); } } break; case 3: if ((insn & (1 << 29)) == 0) { /* Memory move. */ uint32_t dest; /* ??? The docs imply the destination address is loaded into the TEMP register. However the Linux drivers rely on the value being presrved. */ dest = read_dword(s, s->dsp); s->dsp += 4; lsi_memcpy(s, dest, addr, insn & 0xffffff); } else { uint8_t data[7]; int reg; int n; int i; if (insn & (1 << 28)) { addr = s->dsa + sxt24(addr); } n = (insn & 7); reg = (insn >> 16) & 0xff; if (insn & (1 << 24)) { cpu_physical_memory_read(addr, data, n); DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, *(int *)data); for (i = 0; i < n; i++) { lsi_reg_writeb(s, reg + i, data[i]); } } else { DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); for (i = 0; i < n; i++) { data[i] = lsi_reg_readb(s, reg + i); } cpu_physical_memory_write(addr, data, n); } } } /* ??? Need to avoid infinite loops. */ if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { if (s->dcntl & LSI_DCNTL_SSM) { lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); } else { goto again; } } DPRINTF("SCRIPTS execution stopped\n");}static uint8_t lsi_reg_readb(LSIState *s, int offset){ uint8_t tmp;#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;#ifdef DEBUG_LSI_REG DPRINTF("Read reg %x\n", offset);#endif switch (offset) { case 0x00: /* SCNTL0 */ return s->scntl0; case 0x01: /* SCNTL1 */ return s->scntl1; case 0x02: /* SCNTL2 */ return s->scntl2; case 0x03: /* SCNTL3 */ return s->scntl3; case 0x04: /* SCID */ return s->scid; case 0x05: /* SXFER */ return s->sxfer; case 0x06: /* SDID */ return s->sdid; case 0x07: /* GPREG0 */ return 0x7f; case 0xa: /* SSID */ return s->ssid; case 0xb: /* SBCL */ /* ??? This is not correct. However it's (hopefully) only used for diagnostics, so should be ok. */ return 0; case 0xc: /* DSTAT */ tmp = s->dstat | 0x80; if ((s->istat0 & LSI_ISTAT0_INTF) == 0) s->dstat = 0; lsi_update_irq(s); return tmp; case 0x0d: /* SSTAT0 */ return s->sstat0; case 0x0e: /* SSTAT1 */ return s->sstat1; case 0x0f: /* SSTAT2 */ return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; CASE_GET_REG32(dsa, 0x10) case 0x14: /* ISTAT0 */ return s->istat0; case 0x16: /* MBOX0 */ return s->mbox0; case 0x17: /* MBOX1 */ return s->mbox1; case 0x18: /* CTEST0 */ return 0xff; case 0x19: /* CTEST1 */ return 0; case 0x1a: /* CTEST2 */ tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM; if (s->istat0 & LSI_ISTAT0_SIGP) { s->istat0 &= ~LSI_ISTAT0_SIGP; tmp |= LSI_CTEST2_SIGP; } return tmp; case 0x1b: /* CTEST3 */ return s->ctest3; CASE_GET_REG32(temp, 0x1c) case 0x20: /* DFIFO */ return 0; case 0x21: /* CTEST4 */ return s->ctest4; case 0x22: /* CTEST5 */ return s->ctest5; case 0x24: /* DBC[0:7] */ return s->dbc & 0xff; case 0x25: /* DBC[8:15] */ return (s->dbc >> 8) & 0xff; case 0x26: /* DBC[16->23] */ return (s->dbc >> 16) & 0xff; case 0x27: /* DCMD */ return s->dcmd; CASE_GET_REG32(dsp, 0x2c) CASE_GET_REG32(dsps, 0x30) CASE_GET_REG32(scratch[0], 0x34) case 0x38: /* DMODE */ return s->dmode; case 0x39: /* DIEN */ return s->dien; case 0x3b: /* DCNTL */ return s->dcntl; case 0x40: /* SIEN0 */ return s->sien0; case 0x41: /* SIEN1 */ return s->sien1; case 0x42: /* SIST0 */ tmp = s->sist0; s->sist0 = 0; lsi_update_irq(s); return tmp; case 0x43: /* SIST1 */ tmp = s->sist1; s->sist1 = 0; lsi_update_irq(s); return tmp; case 0x47: /* GPCNTL0 */ return 0x0f; case 0x48: /* STIME0 */ return s->stime0; case 0x4a: /* RESPID0 */ return s->respid0; case 0x4b: /* RESPID1 */ return s->respid1; case 0x4d: /* STEST1 */ return s->stest1; case 0x4e: /* STEST2 */ return s->stest2; case 0x4f: /* STEST3 */ return s->stest3; case 0x50: /* SIDL */ /* This is needed by the linux drivers. We currently only update it during the MSG IN phase. */ return s->sidl; case 0x52: /* STEST4 */ return 0xe0; case 0x56: /* CCNTL0 */ return s->ccntl0; case 0x57: /* CCNTL1 */ return s->ccntl1; case 0x58: /* SBDL */ /* Some drivers peek at the data bus during the MSG IN phase. */ if ((s->sstat1 & PHASE_MASK) == PHASE_MI) return s->msg[0]; return 0; case 0x59: /* SBDL high */ return 0; CASE_GET_REG32(mmrs, 0xa0) CASE_GET_REG32(mmws, 0xa4) CASE_GET_REG32(sfs, 0xa8) CASE_GET_REG32(drs, 0xac) CASE_GET_REG32(sbms, 0xb0) CASE_GET_REG32(dmbs, 0xb4) CASE_GET_REG32(dnad64, 0xb8) CASE_GET_REG32(pmjad1, 0xc0) CASE_GET_REG32(pmjad2, 0xc4) CASE_GET_REG32(rbc, 0xc8) CASE_GET_REG32(ua, 0xcc) CASE_GET_REG32(ia, 0xd4) CASE_GET_REG32(sbc, 0xd8) CASE_GET_REG32(csbc, 0xdc) } if (offset >= 0x5c && offset < 0xa0) { int n; int shift; n = (offset - 0x58) >> 2; shift = (offset & 3) * 8; return (s->scratch[n] >> shift) & 0xff; } BADF("readb 0x%x\n", offset); exit(1);#undef CASE_GET_REG32}static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val){#define CASE_SET_REG32(name, addr) \ case addr : s->name &= 0xffffff00; s->name |= val; break; \ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ 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 %x = %02x\n", offset, val);#endif switch (offset) { case 0x00: /* SCNTL0 */ s->scntl0 = val; if (val & LSI_SCNTL0_START) { BADF("Start sequence not implemented\n"); } break; case 0x01: /* SCNTL1 */ s->scntl1 = val & ~LSI_SCNTL1_SST; if (val & LSI_SCNTL1_IARB) { BADF("Immediate Arbritration not implemented\n"); } if (val & LSI_SCNTL1_RST) { s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); } else { s->sstat0 &= ~LSI_SSTAT0_RST; } break; case 0x02: /* SCNTL2 */ val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS); s->scntl3 = val; break; case 0x03: /* SCNTL3 */ s->scntl3 = val; break; case 0x04: /* SCID */ s->scid = val; break; case 0x05: /* SXFER */ s->sxfer = val; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -