diff options
-rw-r--r-- | hw/esp.c | 48 |
1 files changed, 33 insertions, 15 deletions
@@ -127,7 +127,7 @@ struct ESPState { #define STAT_TC 0x10 #define STAT_PE 0x20 #define STAT_GE 0x40 -#define STAT_IN 0x80 +#define STAT_INT 0x80 #define INTR_FC 0x08 #define INTR_BS 0x10 @@ -143,6 +143,22 @@ struct ESPState { #define TCHI_FAS100A 0x4 +static void esp_raise_irq(ESPState *s) +{ + if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { + s->rregs[ESP_RSTAT] |= STAT_INT; + qemu_irq_raise(s->irq); + } +} + +static void esp_lower_irq(ESPState *s) +{ + if (s->rregs[ESP_RSTAT] & STAT_INT) { + s->rregs[ESP_RSTAT] &= ~STAT_INT; + qemu_irq_lower(s->irq); + } +} + static int get_cmd(ESPState *s, uint8_t *buf) { uint32_t dmalen; @@ -171,10 +187,10 @@ static int get_cmd(ESPState *s, uint8_t *buf) if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) { // No such drive - s->rregs[ESP_RSTAT] = STAT_IN; + s->rregs[ESP_RSTAT] = 0; s->rregs[ESP_RINTR] = INTR_DC; s->rregs[ESP_RSEQ] = SEQ_0; - qemu_irq_raise(s->irq); + esp_raise_irq(s); return 0; } s->current_dev = s->scsi_dev[target]; @@ -191,7 +207,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); s->ti_size = datalen; if (datalen != 0) { - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC; + s->rregs[ESP_RSTAT] = STAT_TC; s->dma_left = 0; s->dma_counter = 0; if (datalen > 0) { @@ -204,7 +220,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void handle_satn(ESPState *s) @@ -223,10 +239,10 @@ static void handle_satn_stop(ESPState *s) if (s->cmdlen) { DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); s->do_cmd = 1; - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD; + s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } } @@ -237,7 +253,7 @@ static void write_response(ESPState *s) s->ti_buf[1] = 0; if (s->dma) { s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; } else { @@ -246,18 +262,18 @@ static void write_response(ESPState *s) s->ti_wptr = 0; s->rregs[ESP_RFLAGS] = 2; } - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void esp_dma_done(ESPState *s) { - s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC; + s->rregs[ESP_RSTAT] |= STAT_TC; s->rregs[ESP_RINTR] = INTR_BS; s->rregs[ESP_RSEQ] = 0; s->rregs[ESP_RFLAGS] = 0; s->rregs[ESP_TCLO] = 0; s->rregs[ESP_TCMID] = 0; - qemu_irq_raise(s->irq); + esp_raise_irq(s); } static void esp_do_dma(ESPState *s) @@ -381,6 +397,8 @@ static void esp_reset(void *opaque) { ESPState *s = opaque; + esp_lower_irq(s); + memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a @@ -415,7 +433,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) } else { s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; } - qemu_irq_raise(s->irq); + esp_raise_irq(s); } if (s->ti_size == 0) { s->ti_rptr = 0; @@ -424,8 +442,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) break; case ESP_RINTR: // Clear interrupt/error status bits - s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE); - qemu_irq_lower(s->irq); + s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE); + esp_lower_irq(s); break; default: break; @@ -487,7 +505,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Bus reset (%2.2x)\n", val); s->rregs[ESP_RINTR] = INTR_RST; if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { - qemu_irq_raise(s->irq); + esp_raise_irq(s); } break; case CMD_TI: |