From 9dc0aadae3088a29af32c2ee7165e88c82cdc680 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 11 Jun 2017 19:10:21 +0300 Subject: [PATCH] Masoboshi updates (SCSI write support, true SCSI and IDE DMA support) --- idecontrollers.cpp | 82 ++++++++++++++++++++++++++++++++++++++-------- include/ide.h | 7 ++++ qemuvga/esp.cpp | 66 ++++++++++++++++++++++++++++++------- qemuvga/scsi/esp.h | 3 ++ 4 files changed, 133 insertions(+), 25 deletions(-) diff --git a/idecontrollers.cpp b/idecontrollers.cpp index 447b4c6d..5799205d 100644 --- a/idecontrollers.cpp +++ b/idecontrollers.cpp @@ -264,6 +264,11 @@ void idecontroller_hsync(void) { for (int i = 0; ide_boards[i]; i++) { struct ide_board *board = ide_boards[i]; + if (board->hsync_cnt > 0) { + board->hsync_cnt--; + if (!board->hsync_cnt && board->hsync_code) + board->hsync_code(board); + } if (board->configured) { for (int j = 0; j < MAX_IDE_PORTS_BOARD; j++) { if (board->ide[j]) { @@ -435,6 +440,10 @@ static int get_masoboshi_reg(uaecptr addr, struct ide_board *board) reg |= IDE_SECONDARY; return reg; } +static void masoboshi_ide_dma(struct ide_board *board) +{ + board->state2[0] |= 0x80; +} static int get_adide_reg(uaecptr addr, struct ide_board *board) { @@ -599,7 +608,8 @@ static uae_u32 ide_read_byte(struct ide_board *board, uaecptr addr) v = board->rom[addr & board->rom_mask]; rom = true; } - } else if (addr >= 0xf000 && addr <= 0xf007) { + } else if ((addr >= 0xf000 && addr <= 0xf00f) || (addr >= 0xf100 && addr <= 0xf10f)) { + // scsi dma controller if (board->subtype) v = masoboshi_ncr9x_scsi_get(oaddr, getidenum(board, masoboshi_board)); } else if (addr == 0xf040) { @@ -611,7 +621,7 @@ static uae_u32 ide_read_byte(struct ide_board *board, uaecptr addr) if (board->irq) { v &= ~1; } - v |= masoboshi_ncr9x_scsi_get(oaddr, getidenum(board, masoboshi_board)); + v |= board->state2[0] &0x80; } else if (addr == 0xf047) { v = board->state; } else { @@ -868,6 +878,14 @@ static uae_u32 ide_read_word(struct ide_board *board, uaecptr addr) v = board->rom[addr & board->rom_mask] << 8; v |= board->rom[(addr + 1) & board->rom_mask]; } + } else if (addr == 0xf04c || addr == 0xf14c) { + v = board->dma_ptr >> 16; + } else if (addr == 0xf04e || addr == 0xf14e) { + v = board->dma_ptr; + write_log(_T("MASOBOSHI IDE DMA PTR READ = %08x %08x\n"), board->dma_ptr, M68K_GETPC); + } else if (addr == 0xf04a || addr == 0xf14a) { + v = board->dma_cnt; + write_log(_T("MASOBOSHI IDE DMA LEN READ = %04x %08x\n"), board->dma_cnt, v, M68K_GETPC); } else { int regnum = get_masoboshi_reg(addr, board); if (regnum == IDE_DATA) { @@ -1056,19 +1074,57 @@ static void ide_write_byte(struct ide_board *board, uaecptr addr, uae_u8 v) } else if ((addr >= 0xf000 && addr <= 0xf007)) { if (board->subtype) masoboshi_ncr9x_scsi_put(oaddr, v, getidenum(board, masoboshi_board)); - } else if (addr >= 0xf04a && addr <= 0xf04f) { - // dma controller + } else if (addr >= 0xf00a && addr <= 0xf00f) { + // scsi dma controller masoboshi_ncr9x_scsi_put(oaddr, v, getidenum(board, masoboshi_board)); - } else if (addr >= 0xf040 && addr < 0xf048) { - masoboshi_ncr9x_scsi_put(oaddr, v, getidenum(board, masoboshi_board)); - if (addr == 0xf047) { - board->state = v; - board->intena = (v & 8) != 0; - } - if (addr == 0xf040) { - board->irq = false; + } else if (addr >= 0xf040 && addr <= 0xf04f) { + // ide dma controller + if (addr >= 0xf04c && addr < 0xf050) { + int shift = (3 - (addr - 0xf04c)) * 8; + uae_u32 mask = 0xff << shift; + board->dma_ptr &= ~mask; + board->dma_ptr |= v << shift; + board->dma_ptr &= 0xffffff; + } else if (addr >= 0xf04a && addr < 0xf04c) { + if (addr == 0xf04a) { + board->dma_cnt &= 0x00ff; + board->dma_cnt |= v << 8; + } else { + board->dma_cnt &= 0xff00; + board->dma_cnt |= v; + } + } else if (addr >= 0xf040 && addr < 0xf048) { + board->state2[addr - 0xf040] = v; + board->state2[0] &= ~0x80; + if (addr == 0xf047) { + board->state = v; + board->intena = (v & 8) != 0; + // masoboshi ide dma + if (v & 0x80) { + board->hsync_code = masoboshi_ide_dma; + board->hsync_cnt = (board->dma_cnt / maxhpos) * 2 + 1; + write_log(_T("MASOBOSHI IDE DMA %s start %08x, %d\n"), (board->state2[5] & 0x80) ? _T("READ") : _T("WRITE"), board->dma_ptr, board->dma_cnt); + if (ide_drq_check(board->ide[0])) { + if (!(board->state2[5] & 0x80)) { + for (int i = 0; i < board->dma_cnt; i++) { + put_ide_reg(board, IDE_DATA, get_word(board->dma_ptr & ~1)); + board->dma_ptr += 2; + } + } else { + for (int i = 0; i < board->dma_cnt; i++) { + put_word(board->dma_ptr & ~1, get_ide_reg(board, IDE_DATA)); + board->dma_ptr += 2; + } + } + board->dma_cnt = 0; + } + } + } + if (addr == 0xf040) { + board->state2[0] &= ~0x80; + board->irq = false; + } } - write_log(_T("MASOBOSHI STATUS BYTE PUT %08x %02x %08x\n"), addr, v, M68K_GETPC); } } else if (board->type == APOLLO_IDE) { diff --git a/include/ide.h b/include/ide.h index 06ae06b3..75957844 100644 --- a/include/ide.h +++ b/include/ide.h @@ -27,6 +27,8 @@ struct ide_registers struct ide_thread_state; struct ide_hdf; +typedef void (*hsync_func)(struct ide_board*); + #define MAX_IDE_PORTS_BOARD 3 struct ide_board { @@ -45,10 +47,15 @@ struct ide_board bool intena; bool enabled; int state; + uae_u8 state2[8]; int type; int userdata; int subtype; uae_u16 data_latch; + uae_u32 dma_ptr; + uae_u32 dma_cnt; + int hsync_cnt; + hsync_func hsync_code; struct romconfig *rc, *original_rc; struct ide_board **self_ptr; }; diff --git a/qemuvga/esp.cpp b/qemuvga/esp.cpp index 3bf3556f..416404fe 100644 --- a/qemuvga/esp.cpp +++ b/qemuvga/esp.cpp @@ -211,6 +211,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) s->current_req = scsiesp_req_new(current_lun, 0, lun, buf, s); datalen = scsiesp_req_enqueue(s->current_req); s->ti_size = datalen; + s->transfer_complete = 0; if (datalen != 0) { s->rregs[ESP_RSTAT] = 0; if (s->dma) { @@ -299,23 +300,24 @@ static void write_response(ESPState *s) if (s->dma) { s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; - s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RINTR] = INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; } else { s->ti_size = 2; s->ti_rptr = 0; s->ti_wptr = 0; - //s->rregs[ESP_RFLAGS] = 2; + s->rregs[ESP_RSTAT] |= STAT_MI; + s->rregs[ESP_RINTR] = INTR_FC; } esp_raise_irq(s); } static void esp_dma_done(ESPState *s) { + s->transfer_complete = 1; 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; s->rregs[ESP_TCHI] = 0; @@ -347,13 +349,28 @@ static int esp_do_dma(ESPState *s) len2 = len; s->dma_pending = len2; if (to_device) { - len = s->dma_memory_read(s->dma_opaque, s->async_buf, len2); + len = s->dma_memory_read(s->dma_opaque, s->async_buf, len2); + // if dma counter is larger than transfer size, fill the FIFO + // Masoboshi needs this. + if (len < 0) { + int diff = s->dma_counter - (len2 + s->dma_len); + if (diff > TI_BUFSZ) + diff = TI_BUFSZ; + if (diff > 0) { + s->dma_memory_read(s->dma_opaque, s->ti_buf, diff); + s->ti_rptr = 0; + s->ti_size = diff; + s->ti_wptr = diff; + s->fifo_on = 3; + } + } } else { len = s->dma_memory_write(s->dma_opaque, s->async_buf, len2); } if (len < 0) len = len2; s->dma_left -= len; + s->dma_len += len; s->async_buf += len; s->async_len -= len; if (to_device) @@ -378,6 +395,21 @@ static int esp_do_dma(ESPState *s) return 1; } +void esp_fake_dma_put(void *opaque, uint8_t v) +{ + ESPState *s = (ESPState*)opaque; + if (s->transfer_complete) { + if (!s->fifo_on) { + s->fifo_on = 1; + s->ti_rptr = s->ti_wptr = 0; + s->ti_size = 0; + } + esp_reg_write(opaque, ESP_FIFO, v); + } else { + esp_dma_enable(opaque, 1); + } +} + void esp_fake_dma_done(void *opaque) { ESPState *s = (ESPState*)opaque; @@ -386,6 +418,7 @@ void esp_fake_dma_done(void *opaque) s->dma_pending = 0; s->dma_left -= len; + s->dma_len += len; s->async_buf += len; s->async_len -= len; if (to_device) @@ -403,9 +436,12 @@ void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid) { ESPState *s = (ESPState*)req->hba_private; + bool dma = s->dma != 0; - s->fifo_on = 0; - s->ti_size = 0; + if (s->fifo_on != 3) { + s->fifo_on = 0; + s->ti_size = 0; + } s->dma_left = 0; s->dma_pending = 0; s->async_len = 0; @@ -413,6 +449,9 @@ void esp_command_complete(SCSIRequest *req, uint32_t status, fas408_check(s); s->rregs[ESP_RSTAT] = STAT_ST; esp_dma_done(s); + // TC is not set if transfer stopped due to phase change, not counter becoming zero. + if (dma && s->dma_len < s->dma_counter) + s->rregs[ESP_RSTAT] &= ~STAT_TC; if (s->current_req) { scsiesp_req_unref(s->current_req); s->current_req = NULL; @@ -446,6 +485,7 @@ static int handle_ti(ESPState *s) uint32_t dmalen, minlen; s->fifo_on = 1; + s->transfer_complete = 0; fas408_check(s); @@ -469,8 +509,10 @@ static int handle_ti(ESPState *s) else minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; if (s->dma) { - if (s->dma == 1) + if (s->dma == 1) { s->dma_left = minlen; + s->dma_len = 0; + } s->dma = 2; s->rregs[ESP_RSTAT] &= ~STAT_TC; if (!esp_do_dma(s)) { @@ -620,7 +662,7 @@ uint64_t esp_reg_read(void *opaque, uint32_t saddr) else v = s->ti_size; } - if (!s->dma && v > 1 && s->fifo_on != 2) + if (!s->dma && v > 1 && s->fifo_on < 2) v = 1; return v | (s->rregs[ESP_RSEQ] << 5); } @@ -687,10 +729,12 @@ void esp_reg_write(void *opaque, uint32_t saddr, uint64_t val) break; case ESP_FIFO: if (s->do_cmd) { + if (s->cmdlen >= TI_BUFSZ) + return; s->cmdbuf[s->cmdlen++] = val & 0xff; - } else if (s->ti_size == TI_BUFSZ - 1) { - ; } else { + if (s->ti_wptr >= TI_BUFSZ) + return; s->ti_size++; s->ti_buf[s->ti_wptr++] = val & 0xff; } @@ -734,8 +778,6 @@ void esp_reg_write(void *opaque, uint32_t saddr, uint64_t val) break; case CMD_ICCS: write_response(s); - s->rregs[ESP_RINTR] = INTR_FC; - s->rregs[ESP_RSTAT] |= STAT_MI; break; case CMD_MSGACC: s->rregs[ESP_RINTR] = INTR_DC; diff --git a/qemuvga/scsi/esp.h b/qemuvga/scsi/esp.h index 8431f759..a8cf90b9 100644 --- a/qemuvga/scsi/esp.h +++ b/qemuvga/scsi/esp.h @@ -22,6 +22,7 @@ struct ESPState { int irq_raised; uint8_t chip_id; int32_t ti_size; + int32_t dma_len; uint32_t ti_rptr, ti_wptr; uint32_t status; uint32_t dma; @@ -42,6 +43,7 @@ struct ESPState { int dma_enabled; int pio_on; int fifo_on; + int transfer_complete; uint32_t async_len; uint8_t *async_buf; @@ -203,6 +205,7 @@ void esp_reg_write(void *s, uint32_t saddr, uint64_t val); void esp_dma_enable(void *opaque, int level); void esp_fake_dma_done(void *opaque); +void esp_fake_dma_put(void *opaque, uint8_t v); void esp_request_cancelled(SCSIRequest *req); void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid); -- 2.47.3