/*
* QEMU ESP/NCR53C9x emulation
- *
+ *
* Copyright (c) 2005-2006 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
#define DPRINTF(fmt, args...)
#endif
-#define ESP_MAXREG 0x3f
+#define ESP_MASK 0x3f
+#define ESP_REGS 16
+#define ESP_SIZE (ESP_REGS * 4)
#define TI_BUFSZ 32
/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
#define ESP_MAX_DEVS 7
typedef struct ESPState ESPState;
struct ESPState {
+ qemu_irq irq;
BlockDriverState **bd;
- uint8_t rregs[ESP_MAXREG];
- uint8_t wregs[ESP_MAXREG];
+ uint8_t rregs[ESP_REGS];
+ uint8_t wregs[ESP_REGS];
int32_t ti_size;
uint32_t ti_rptr, ti_wptr;
uint8_t ti_buf[TI_BUFSZ];
if (s->dma) {
espdma_memory_read(s->dma_opaque, buf, dmalen);
} else {
- buf[0] = 0;
- memcpy(&buf[1], s->ti_buf, dmalen);
- dmalen++;
+ buf[0] = 0;
+ memcpy(&buf[1], s->ti_buf, dmalen);
+ dmalen++;
}
s->ti_size = 0;
if (target >= MAX_DISKS || !s->scsi_dev[target]) {
// No such drive
- s->rregs[4] = STAT_IN;
- s->rregs[5] = INTR_DC;
- s->rregs[6] = SEQ_0;
- espdma_raise_irq(s->dma_opaque);
- return 0;
+ s->rregs[4] = STAT_IN;
+ s->rregs[5] = INTR_DC;
+ s->rregs[6] = SEQ_0;
+ qemu_irq_raise(s->irq);
+ return 0;
}
s->current_dev = s->scsi_dev[target];
return dmalen;
}
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
- espdma_raise_irq(s->dma_opaque);
+ qemu_irq_raise(s->irq);
}
static void handle_satn(ESPState *s)
s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
- espdma_raise_irq(s->dma_opaque);
+ qemu_irq_raise(s->irq);
}
}
s->ti_buf[1] = 0;
if (s->dma) {
espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
- s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
- s->rregs[5] = INTR_BS | INTR_FC;
- s->rregs[6] = SEQ_CD;
+ s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
+ s->rregs[5] = INTR_BS | INTR_FC;
+ s->rregs[6] = SEQ_CD;
} else {
- s->ti_size = 2;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->rregs[7] = 2;
+ s->ti_size = 2;
+ s->ti_rptr = 0;
+ s->ti_wptr = 0;
+ s->rregs[7] = 2;
}
- espdma_raise_irq(s->dma_opaque);
+ qemu_irq_raise(s->irq);
}
static void esp_dma_done(ESPState *s)
s->rregs[7] = 0;
s->rregs[0] = 0;
s->rregs[1] = 0;
- espdma_raise_irq(s->dma_opaque);
+ qemu_irq_raise(s->irq);
}
static void esp_do_dma(ESPState *s)
}
}
-void esp_reset(void *opaque)
+static void esp_reset(void *opaque)
{
ESPState *s = opaque;
- memset(s->rregs, 0, ESP_MAXREG);
- memset(s->wregs, 0, ESP_MAXREG);
+ memset(s->rregs, 0, ESP_REGS);
+ memset(s->wregs, 0, ESP_REGS);
s->rregs[0x0e] = 0x4; // Indicate fas100a
s->ti_size = 0;
s->ti_rptr = 0;
s->do_cmd = 0;
}
+static void parent_esp_reset(void *opaque, int irq, int level)
+{
+ if (level)
+ esp_reset(opaque);
+}
+
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
- saddr = (addr & ESP_MAXREG) >> 2;
+ saddr = (addr & ESP_MASK) >> 2;
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
switch (saddr) {
case 2:
- // FIFO
- if (s->ti_size > 0) {
- s->ti_size--;
+ // FIFO
+ if (s->ti_size > 0) {
+ s->ti_size--;
if ((s->rregs[4] & 6) == 0) {
/* Data in/out. */
fprintf(stderr, "esp: PIO data read not implemented\n");
} else {
s->rregs[2] = s->ti_buf[s->ti_rptr++];
}
- espdma_raise_irq(s->dma_opaque);
- }
- if (s->ti_size == 0) {
+ qemu_irq_raise(s->irq);
+ }
+ if (s->ti_size == 0) {
s->ti_rptr = 0;
s->ti_wptr = 0;
}
- break;
+ break;
case 5:
// interrupt
// Clear interrupt/error status bits
s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
- espdma_clear_irq(s->dma_opaque);
+ qemu_irq_lower(s->irq);
break;
default:
- break;
+ break;
}
return s->rregs[saddr];
}
ESPState *s = opaque;
uint32_t saddr;
- saddr = (addr & ESP_MAXREG) >> 2;
+ saddr = (addr & ESP_MASK) >> 2;
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
switch (saddr) {
case 0:
s->rregs[4] &= ~STAT_TC;
break;
case 2:
- // FIFO
+ // FIFO
if (s->do_cmd) {
s->cmdbuf[s->cmdlen++] = val & 0xff;
} else if ((s->rregs[4] & 6) == 0) {
s->ti_size++;
s->ti_buf[s->ti_wptr++] = val & 0xff;
}
- break;
+ break;
case 3:
s->rregs[saddr] = val;
- // Command
- if (val & 0x80) {
- s->dma = 1;
+ // Command
+ if (val & 0x80) {
+ s->dma = 1;
/* Reload DMA counter. */
s->rregs[0] = s->wregs[0];
s->rregs[1] = s->wregs[1];
- } else {
- s->dma = 0;
- }
- switch(val & 0x7f) {
- case 0:
- DPRINTF("NOP (%2.2x)\n", val);
- break;
- case 1:
- DPRINTF("Flush FIFO (%2.2x)\n", val);
+ } else {
+ s->dma = 0;
+ }
+ switch(val & 0x7f) {
+ case 0:
+ DPRINTF("NOP (%2.2x)\n", val);
+ break;
+ case 1:
+ DPRINTF("Flush FIFO (%2.2x)\n", val);
//s->ti_size = 0;
- s->rregs[5] = INTR_FC;
- s->rregs[6] = 0;
- break;
- case 2:
- DPRINTF("Chip reset (%2.2x)\n", val);
- esp_reset(s);
- break;
- case 3:
- DPRINTF("Bus reset (%2.2x)\n", val);
- s->rregs[5] = INTR_RST;
+ s->rregs[5] = INTR_FC;
+ s->rregs[6] = 0;
+ break;
+ case 2:
+ DPRINTF("Chip reset (%2.2x)\n", val);
+ esp_reset(s);
+ break;
+ case 3:
+ DPRINTF("Bus reset (%2.2x)\n", val);
+ s->rregs[5] = INTR_RST;
if (!(s->wregs[8] & 0x40)) {
- espdma_raise_irq(s->dma_opaque);
+ qemu_irq_raise(s->irq);
}
- break;
- case 0x10:
- handle_ti(s);
- break;
- case 0x11:
- DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
- write_response(s);
- break;
- case 0x12:
- DPRINTF("Message Accepted (%2.2x)\n", val);
- write_response(s);
- s->rregs[5] = INTR_DC;
- s->rregs[6] = 0;
- break;
- case 0x1a:
- DPRINTF("Set ATN (%2.2x)\n", val);
- break;
- case 0x42:
- DPRINTF("Set ATN (%2.2x)\n", val);
- handle_satn(s);
- break;
- case 0x43:
- DPRINTF("Set ATN & stop (%2.2x)\n", val);
- handle_satn_stop(s);
- break;
- default:
- DPRINTF("Unhandled ESP command (%2.2x)\n", val);
- break;
- }
- break;
+ break;
+ case 0x10:
+ handle_ti(s);
+ break;
+ case 0x11:
+ DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
+ write_response(s);
+ break;
+ case 0x12:
+ DPRINTF("Message Accepted (%2.2x)\n", val);
+ write_response(s);
+ s->rregs[5] = INTR_DC;
+ s->rregs[6] = 0;
+ break;
+ case 0x1a:
+ DPRINTF("Set ATN (%2.2x)\n", val);
+ break;
+ case 0x42:
+ DPRINTF("Set ATN (%2.2x)\n", val);
+ handle_satn(s);
+ break;
+ case 0x43:
+ DPRINTF("Set ATN & stop (%2.2x)\n", val);
+ handle_satn_stop(s);
+ break;
+ case 0x44:
+ DPRINTF("Enable selection (%2.2x)\n", val);
+ break;
+ default:
+ DPRINTF("Unhandled ESP command (%2.2x)\n", val);
+ break;
+ }
+ break;
case 4 ... 7:
- break;
+ break;
case 8:
s->rregs[saddr] = val;
break;
s->rregs[saddr] = val;
break;
default:
- break;
+ break;
}
s->wregs[saddr] = val;
}
{
ESPState *s = opaque;
- qemu_put_buffer(f, s->rregs, ESP_MAXREG);
- qemu_put_buffer(f, s->wregs, ESP_MAXREG);
+ qemu_put_buffer(f, s->rregs, ESP_REGS);
+ qemu_put_buffer(f, s->wregs, ESP_REGS);
qemu_put_be32s(f, &s->ti_size);
qemu_put_be32s(f, &s->ti_rptr);
qemu_put_be32s(f, &s->ti_wptr);
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
ESPState *s = opaque;
-
+
if (version_id != 3)
return -EINVAL; // Cannot emulate 2
- qemu_get_buffer(f, s->rregs, ESP_MAXREG);
- qemu_get_buffer(f, s->wregs, ESP_MAXREG);
+ qemu_get_buffer(f, s->rregs, ESP_REGS);
+ qemu_get_buffer(f, s->wregs, ESP_REGS);
qemu_get_be32s(f, &s->ti_size);
qemu_get_be32s(f, &s->ti_rptr);
qemu_get_be32s(f, &s->ti_wptr);
s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
}
-void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
+void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+ void *dma_opaque, qemu_irq irq, qemu_irq *reset)
{
ESPState *s;
int esp_io_memory;
return NULL;
s->bd = bd;
+ s->irq = irq;
s->dma_opaque = dma_opaque;
esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
- cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
+ cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory);
esp_reset(s);
register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
+ *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1);
+
return s;
}