⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lsi53c895a.c

📁 qemu性能直逼VMware的仿真器QEMU 的模擬速度約為實機的 25%;約為 Bochs 的 60 倍。Plex86、User-Mode-Linux、VMware 和 Virtual PC 則比
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  * QEMU LSI53C895A SCSI Host Bus Adapter emulation * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook * * This code is licenced under the LGPL. *//* ??? Need to check if the {read,write}[wl] routines work properly on   big-endian targets.  */#include "vl.h"//#define DEBUG_LSI//#define DEBUG_LSI_REG#ifdef DEBUG_LSI#define DPRINTF(fmt, args...) \do { printf("lsi_scsi: " fmt , ##args); } while (0)#define BADF(fmt, args...) \do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args); exit(1);} while (0)#else#define DPRINTF(fmt, args...) do {} while(0)#define BADF(fmt, args...) \do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0)#endif#define LSI_SCNTL0_TRG    0x01#define LSI_SCNTL0_AAP    0x02#define LSI_SCNTL0_EPC    0x08#define LSI_SCNTL0_WATN   0x10#define LSI_SCNTL0_START  0x20#define LSI_SCNTL1_SST    0x01#define LSI_SCNTL1_IARB   0x02#define LSI_SCNTL1_AESP   0x04#define LSI_SCNTL1_RST    0x08#define LSI_SCNTL1_CON    0x10#define LSI_SCNTL1_DHP    0x20#define LSI_SCNTL1_ADB    0x40#define LSI_SCNTL1_EXC    0x80#define LSI_SCNTL2_WSR    0x01#define LSI_SCNTL2_VUE0   0x02#define LSI_SCNTL2_VUE1   0x04#define LSI_SCNTL2_WSS    0x08#define LSI_SCNTL2_SLPHBEN 0x10#define LSI_SCNTL2_SLPMD  0x20#define LSI_SCNTL2_CHM    0x40#define LSI_SCNTL2_SDU    0x80#define LSI_ISTAT0_DIP    0x01#define LSI_ISTAT0_SIP    0x02#define LSI_ISTAT0_INTF   0x04#define LSI_ISTAT0_CON    0x08#define LSI_ISTAT0_SEM    0x10#define LSI_ISTAT0_SIGP   0x20#define LSI_ISTAT0_SRST   0x40#define LSI_ISTAT0_ABRT   0x80#define LSI_ISTAT1_SI     0x01#define LSI_ISTAT1_SRUN   0x02#define LSI_ISTAT1_FLSH   0x04#define LSI_SSTAT0_SDP0   0x01#define LSI_SSTAT0_RST    0x02#define LSI_SSTAT0_WOA    0x04#define LSI_SSTAT0_LOA    0x08#define LSI_SSTAT0_AIP    0x10#define LSI_SSTAT0_OLF    0x20#define LSI_SSTAT0_ORF    0x40#define LSI_SSTAT0_ILF    0x80#define LSI_SIST0_PAR     0x01#define LSI_SIST0_RST     0x02#define LSI_SIST0_UDC     0x04#define LSI_SIST0_SGE     0x08#define LSI_SIST0_RSL     0x10#define LSI_SIST0_SEL     0x20#define LSI_SIST0_CMP     0x40#define LSI_SIST0_MA      0x80#define LSI_SIST1_HTH     0x01#define LSI_SIST1_GEN     0x02#define LSI_SIST1_STO     0x04#define LSI_SIST1_SBMC    0x10#define LSI_SOCL_IO       0x01#define LSI_SOCL_CD       0x02#define LSI_SOCL_MSG      0x04#define LSI_SOCL_ATN      0x08#define LSI_SOCL_SEL      0x10#define LSI_SOCL_BSY      0x20#define LSI_SOCL_ACK      0x40#define LSI_SOCL_REQ      0x80#define LSI_DSTAT_IID     0x01#define LSI_DSTAT_SIR     0x04#define LSI_DSTAT_SSI     0x08#define LSI_DSTAT_ABRT    0x10#define LSI_DSTAT_BF      0x20#define LSI_DSTAT_MDPE    0x40#define LSI_DSTAT_DFE     0x80#define LSI_DCNTL_COM     0x01#define LSI_DCNTL_IRQD    0x02#define LSI_DCNTL_STD     0x04#define LSI_DCNTL_IRQM    0x08#define LSI_DCNTL_SSM     0x10#define LSI_DCNTL_PFEN    0x20#define LSI_DCNTL_PFF     0x40#define LSI_DCNTL_CLSE    0x80#define LSI_DMODE_MAN     0x01#define LSI_DMODE_BOF     0x02#define LSI_DMODE_ERMP    0x04#define LSI_DMODE_ERL     0x08#define LSI_DMODE_DIOM    0x10#define LSI_DMODE_SIOM    0x20#define LSI_CTEST2_DACK   0x01#define LSI_CTEST2_DREQ   0x02#define LSI_CTEST2_TEOP   0x04#define LSI_CTEST2_PCICIE 0x08#define LSI_CTEST2_CM     0x10#define LSI_CTEST2_CIO    0x20#define LSI_CTEST2_SIGP   0x40#define LSI_CTEST2_DDIR   0x80#define LSI_CTEST5_BL2    0x04#define LSI_CTEST5_DDIR   0x08#define LSI_CTEST5_MASR   0x10#define LSI_CTEST5_DFSN   0x20#define LSI_CTEST5_BBCK   0x40#define LSI_CTEST5_ADCK   0x80#define LSI_CCNTL0_DILS   0x01#define LSI_CCNTL0_DISFC  0x10#define LSI_CCNTL0_ENNDJ  0x20#define LSI_CCNTL0_PMJCTL 0x40#define LSI_CCNTL0_ENPMJ  0x80#define PHASE_DO          0#define PHASE_DI          1#define PHASE_CMD         2#define PHASE_ST          3#define PHASE_MO          6#define PHASE_MI          7#define PHASE_MASK        7/* The HBA is ID 7, so for simplicitly limit to 7 devices.  */#define LSI_MAX_DEVS      7/* Maximum length of MSG IN data.  */#define LSI_MAX_MSGIN_LEN 8/* Flag set if this is a tagged command.  */#define LSI_TAG_VALID     (1 << 16)typedef struct {    uint32_t tag;    uint32_t pending;    int out;} lsi_queue;typedef struct {    PCIDevice pci_dev;    int mmio_io_addr;    int ram_io_addr;    uint32_t script_ram_base;    int carry; /* ??? Should this be an a visible register somewhere?  */    int sense;    /* Action to take at the end of a MSG IN phase.       0 = COMMAND, 1 = disconect, 2 = DATA OUT, 3 = DATA IN.  */    int msg_action;    int msg_len;    uint8_t msg[LSI_MAX_MSGIN_LEN];    /* 0 if SCRIPTS are running or stopped.     * 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;    SCSIDevice *scsi_dev[LSI_MAX_DEVS];    SCSIDevice *current_dev;    int current_lun;    /* The tag is a combination of the device ID and the SCSI tag.  */    uint32_t current_tag;    uint32_t current_dma_len;    uint8_t *dma_buf;    lsi_queue *queue;    int queue_len;    int active_commands;    uint32_t dsa;    uint32_t temp;    uint32_t dnad;    uint32_t dbc;    uint8_t istat0;    uint8_t istat1;    uint8_t dcmd;    uint8_t dstat;    uint8_t dien;    uint8_t sist0;    uint8_t sist1;    uint8_t sien0;    uint8_t sien1;    uint8_t mbox0;    uint8_t mbox1;    uint8_t dfifo;    uint8_t ctest3;    uint8_t ctest4;    uint8_t ctest5;    uint8_t ccntl0;    uint8_t ccntl1;    uint32_t dsp;    uint32_t dsps;    uint8_t dmode;    uint8_t dcntl;    uint8_t scntl0;    uint8_t scntl1;    uint8_t scntl2;    uint8_t scntl3;    uint8_t sstat0;    uint8_t sstat1;    uint8_t scid;    uint8_t sxfer;    uint8_t socl;    uint8_t sdid;    uint8_t ssid;    uint8_t sfbr;    uint8_t stest1;    uint8_t stest2;    uint8_t stest3;    uint8_t sidl;    uint8_t stime0;    uint8_t respid0;    uint8_t respid1;    uint32_t mmrs;    uint32_t mmws;    uint32_t sfs;    uint32_t drs;    uint32_t sbms;    uint32_t dmbs;    uint32_t dnad64;    uint32_t pmjad1;    uint32_t pmjad2;    uint32_t rbc;    uint32_t ua;    uint32_t ia;    uint32_t sbc;    uint32_t csbc;    uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */    /* Script ram is stored as 32-bit words in host byteorder.  */    uint32_t script_ram[2048];} LSIState;static void lsi_soft_reset(LSIState *s){    DPRINTF("Reset\n");    s->carry = 0;    s->waiting = 0;    s->dsa = 0;    s->dnad = 0;    s->dbc = 0;    s->temp = 0;    memset(s->scratch, 0, sizeof(s->scratch));    s->istat0 = 0;    s->istat1 = 0;    s->dcmd = 0;    s->dstat = 0;    s->dien = 0;    s->sist0 = 0;    s->sist1 = 0;    s->sien0 = 0;    s->sien1 = 0;    s->mbox0 = 0;    s->mbox1 = 0;    s->dfifo = 0;    s->ctest3 = 0;    s->ctest4 = 0;    s->ctest5 = 0;    s->ccntl0 = 0;    s->ccntl1 = 0;    s->dsp = 0;    s->dsps = 0;    s->dmode = 0;    s->dcntl = 0;    s->scntl0 = 0xc0;    s->scntl1 = 0;    s->scntl2 = 0;    s->scntl3 = 0;    s->sstat0 = 0;    s->sstat1 = 0;    s->scid = 7;    s->sxfer = 0;    s->socl = 0;    s->stest1 = 0;    s->stest2 = 0;    s->stest3 = 0;    s->sidl = 0;    s->stime0 = 0;    s->respid0 = 0x80;    s->respid1 = 0;    s->mmrs = 0;    s->mmws = 0;    s->sfs = 0;    s->drs = 0;    s->sbms = 0;    s->dmbs = 0;    s->dnad64 = 0;    s->pmjad1 = 0;    s->pmjad2 = 0;    s->rbc = 0;    s->ua = 0;    s->ia = 0;    s->sbc = 0;    s->csbc = 0;}static uint8_t lsi_reg_readb(LSIState *s, int offset);static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);static void lsi_execute_script(LSIState *s);static inline uint32_t read_dword(LSIState *s, uint32_t addr){    uint32_t buf;    /* Optimize reading from SCRIPTS RAM.  */    if ((addr & 0xffffe000) == s->script_ram_base) {        return s->script_ram[(addr & 0x1fff) >> 2];    }    cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);    return cpu_to_le32(buf);}static void lsi_stop_script(LSIState *s){    s->istat1 &= ~LSI_ISTAT1_SRUN;}static void lsi_update_irq(LSIState *s){    int level;    static int last_level;    /* It's unclear whether the DIP/SIP bits should be cleared when the       Interrupt Status Registers are cleared or when istat0 is read.       We currently do the formwer, which seems to work.  */    level = 0;    if (s->dstat) {        if (s->dstat & s->dien)            level = 1;        s->istat0 |= LSI_ISTAT0_DIP;    } else {        s->istat0 &= ~LSI_ISTAT0_DIP;    }    if (s->sist0 || s->sist1) {        if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))            level = 1;        s->istat0 |= LSI_ISTAT0_SIP;    } else {        s->istat0 &= ~LSI_ISTAT0_SIP;    }    if (s->istat0 & LSI_ISTAT0_INTF)        level = 1;    if (level != last_level) {        DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",                level, s->dstat, s->sist1, s->sist0);        last_level = level;    }    pci_set_irq(&s->pci_dev, 0, level);}/* Stop SCRIPTS execution and raise a SCSI interrupt.  */static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1){    uint32_t mask0;    uint32_t mask1;    DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",            stat1, stat0, s->sist1, s->sist0);    s->sist0 |= stat0;    s->sist1 |= stat1;    /* Stop processor on fatal or unmasked interrupt.  As a special hack       we don't stop processing when raising STO.  Instead continue       execution and stop at the next insn that accesses the SCSI bus.  */    mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);    mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);    mask1 &= ~LSI_SIST1_STO;    if (s->sist0 & mask0 || s->sist1 & mask1) {        lsi_stop_script(s);    }    lsi_update_irq(s);}/* Stop SCRIPTS execution and raise a DMA interrupt.  */static void lsi_script_dma_interrupt(LSIState *s, int stat){    DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);    s->dstat |= stat;    lsi_update_irq(s);    lsi_stop_script(s);}static inline void lsi_set_phase(LSIState *s, int phase){    s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;}static void lsi_bad_phase(LSIState *s, int out, int new_phase){    /* Trigger a phase mismatch.  */    if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {        if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) {            s->dsp = s->pmjad1;        } else {            s->dsp = s->pmjad2;        }        DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);    } else {        DPRINTF("Phase mismatch interrupt\n");        lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);        lsi_stop_script(s);    }    lsi_set_phase(s, new_phase);}/* Resume SCRIPTS execution after a DMA operation.  */static void lsi_resume_script(LSIState *s){    if (s->waiting != 2) {        s->waiting = 0;        lsi_execute_script(s);    } else {        s->waiting = 0;    }}/* Initiate a SCSI layer data transfer.  */static void lsi_do_dma(LSIState *s, int out){    uint32_t count;    uint32_t addr;    if (!s->current_dma_len) {        /* Wait until data is available.  */        DPRINTF("DMA no data available\n");        return;    }    count = s->dbc;    if (count > s->current_dma_len)        count = s->current_dma_len;    DPRINTF("DMA addr=0x%08x len=%d\n", s->dnad, count);    addr = s->dnad;    s->csbc += count;    s->dnad += count;    s->dbc -= count;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -