]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Masoboshi updates (SCSI write support, true SCSI and IDE DMA support)
authorToni Wilen <twilen@winuae.net>
Sun, 11 Jun 2017 16:10:21 +0000 (19:10 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 11 Jun 2017 16:10:21 +0000 (19:10 +0300)
idecontrollers.cpp
include/ide.h
qemuvga/esp.cpp
qemuvga/scsi/esp.h

index 447b4c6dbbc24827af2b492ef97937b82262239a..5799205df255fb5e2ee634c51f7775dba75cf77c 100644 (file)
@@ -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) {
index 06ae06b310f1da7731a938e19276cab9a56416f2..759578447907f9a000b68a10411cb5c72ff3d6fc 100644 (file)
@@ -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;
 };
index 3bf3556fc65b97c8b258b2cfa0b3b438fed89b9e..416404fe22e7f6e250982e2b1518b65e8127f784 100644 (file)
@@ -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;
index 8431f759c62615d19851db267e96bb594ae88788..a8cf90b90ffc3acf68729709ff2dae4a7b2b8831 100644 (file)
@@ -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);