int dma_pulse_DRQ(int ch, Bit8u * buf) { int ret = DMA_DACK; if (MASKED(DI(ch), CI(ch))) { q_printf("DMA: channel %i masked, DRQ ignored\n", ch); ret = DMA_NO_DACK; } if ((dma[DI(ch)].status & 0xf0) || dma[DI(ch)].request) { error("DMA: channel %i already active! (m=%#x s=%#x r=%#x)\n", ch, dma[DI(ch)].chans[CI(ch)].mode, dma[DI(ch)].status, dma[DI(ch)].request); ret = DMA_NO_DACK; } #if 0 q_printf("DMA: pulse DRQ on channel %d\n", ch); #endif if (ret == DMA_DACK) { DMA_LOCK(); dma[DI(ch)].status |= 1 << (CI(ch) + 4); memcpy(dma_data_bus, buf, 1 << DI(ch)); dma_run_channel(DI(ch), CI(ch)); memcpy(buf, dma_data_bus, 1 << DI(ch)); DMA_UNLOCK(); } else { memset(buf, 0xff, 1 << DI(ch)); } return ret; }
static void dma_process_channel(int dma_idx, int chan_idx) { struct dma_channel *chan = &dma[dma_idx].chans[chan_idx]; void *addr = physaddr_to_unixaddr( (chan->page << 16) | (chan->cur_addr.value << dma_idx)); /* first, do the transfer */ switch (DMA_TRANSFER_OP(chan->mode)) { case VERIFY: q_printf("DMA: verify mode does nothing\n"); break; case WRITE: memcpy(addr, dma_data_bus, 1 << dma_idx); break; case READ: memcpy(dma_data_bus, addr, 1 << dma_idx); break; case INVALID: q_printf("DMA: invalid mode does nothing\n"); break; } /* now advance the address */ if ((dma[dma_idx].command & 3) != 3) chan->cur_addr.value += (DMA_ADDR_DEC(chan->mode) ? -1 : 1); /* and the counter */ chan->cur_count.value--; if (chan->cur_count.value == 0xffff) { /* overflow */ if (DMA_AUTOINIT(chan->mode)) { q_printf("DMA: controller %i, channel %i reinitialized\n", dma_idx, chan_idx); chan->cur_addr.value = chan->base_addr.value; chan->cur_count.value = chan->base_count.value; } else { /* TC */ q_printf("DMA: controller %i, channel %i TC\n", dma_idx, chan_idx); dma[dma_idx].status |= 1 << chan_idx; dma[dma_idx].request &= ~(1 << chan_idx); /* the datasheet says it gets automatically masked too */ dma[dma_idx].mask |= 1 << chan_idx; } } }
static void dma_process_channel(int dma_idx, int chan_idx) { struct dma_channel *chan = &dma[dma_idx].chans[chan_idx]; Bit32u addr = (chan->page << 16) | (chan->cur_addr.value << dma_idx); Bit8u mode = chan->mode; /* first, do the transfer */ switch (mode & 3) { case 0: /* verify */ q_printf("DMA: verify mode does nothing\n"); break; case 1: /* write */ MEMCPY_2DOS(addr, dma_data_bus, 1 << dma_idx); break; case 2: /* read */ MEMCPY_2UNIX(dma_data_bus, addr, 1 << dma_idx); break; case 3: /* invalid */ q_printf("DMA: invalid mode does nothing\n"); break; } /* now advance the address */ if (!(dma[dma_idx].command & 2)) chan->cur_addr.value += (mode & 8) ? -1 : 1; /* and the counter */ chan->cur_count.value--; if (chan->cur_count.value == 0xffff) { /* overflow */ if (mode & 4) { /* auto-init */ q_printf("DMA: controller %i, channel %i reinitialized\n", dma_idx, chan_idx); chan->cur_addr.value = chan->base_addr.value; chan->cur_count.value = chan->base_count.value; } else { /* eop */ q_printf("DMA: controller %i, channel %i EOP\n", dma_idx, chan_idx); dma[dma_idx].status |= 1 << chan_idx; dma[dma_idx].request &= ~(1 << chan_idx); /* the datasheet says it gets automatically masked too */ dma[dma_idx].mask |= 1 << chan_idx; } } }
static void dma_soft_reset(int dma_idx) { dma[dma_idx].command = 0; dma[dma_idx].status = 0; dma[dma_idx].request = 0; dma[dma_idx].tmp_reg = 0; dma[dma_idx].ff = 0; dma[dma_idx].mask = 0x0f; q_printf("DMA: Soft Reset on controller %i\n", dma_idx); }
void dma_init(void) { emu_iodev_t io_device; /* 8237 DMA controller */ io_device.read_portb = dma_io_read; io_device.write_portb = dma_io_write; io_device.read_portw = NULL; io_device.write_portw = NULL; io_device.read_portd = NULL; io_device.write_portd = NULL; io_device.irq = EMU_NO_IRQ; io_device.fd = -1; /* * XT Controller */ io_device.start_addr = 0x0000; io_device.end_addr = 0x000F; io_device.handler_name = "DMA - XT Controller"; port_register_handler(io_device, 0); /* * Page Registers (XT) */ io_device.start_addr = 0x0081; io_device.end_addr = 0x0087; io_device.handler_name = "DMA - XT Pages"; port_register_handler(io_device, 0); /* * AT Controller */ io_device.start_addr = 0x00C0; io_device.end_addr = 0x00DE; io_device.handler_name = "DMA - AT Controller"; port_register_handler(io_device, 0); /* * Page Registers (AT) */ io_device.start_addr = 0x0089; io_device.end_addr = 0x008F; io_device.handler_name = "DMA - AT Pages"; port_register_handler(io_device, 0); q_printf("DMA: DMA Controller initialized - 8 & 16 bit modes\n"); }
static void dma_run_channel(int dma_idx, int chan_idx) { int done = 0; long ticks = 0; while (!done && (HAVE_DRQ(dma_idx, chan_idx) || SW_ACTIVE(dma_idx, chan_idx))) { if (!MASKED(dma_idx, chan_idx) && !REACHED_TC(dma_idx, chan_idx) && !(dma[dma_idx].command & 4) && (DMA_TRANSFER_MODE(dma[dma_idx].chans[chan_idx].mode) != CASCADE)) { dma_process_channel(dma_idx, chan_idx); ticks++; } else { done = 1; } dma_update_DRQ(dma_idx, chan_idx); } if (ticks > 1) q_printf("DMA: processed %lu (left %u) cycles on controller %i channel %i\n", ticks, dma[dma_idx].chans[chan_idx].cur_count.value, dma_idx, chan_idx); }
static void dma_io_write(ioport_t port, Bit8u value) { switch (port) { #define HANDLE_ADDR_WRITE(d_n, c_n) \ case DMA##d_n##_ADDR_##c_n: \ dma[d(d_n)].chans[d(c_n)].base_addr.byte[dma[d(d_n)].ff] = value; \ dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff] = value; \ q_printf("DMA%i: addr write: %#x to Channel %d byte %d\n", \ d_n, value, d(c_n), dma[d(d_n)].ff); \ dma[d(d_n)].ff ^= 1; \ break HANDLE_X(ADDR_WRITE); #define HANDLE_CNT_WRITE(d_n, c_n) \ case DMA##d_n##_CNT_##c_n: \ dma[d(d_n)].chans[d(c_n)].base_count.byte[dma[d(d_n)].ff] = value; \ dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff] = value; \ q_printf("DMA%i: count write: %#x to Channel %d byte %d\n", \ d_n, value, d(c_n), dma[d(d_n)].ff); \ dma[d(d_n)].ff ^= 1; \ break HANDLE_X(CNT_WRITE); #define HANDLE_PAGE_WRITE(d_n, c_n) \ case DMA##d_n##_PAGE_##c_n: \ dma[d(d_n)].chans[d(c_n)].page = value; \ q_printf("DMA%i: page write: %#x to Channel %d\n", \ d_n, value, d(c_n)); \ break HANDLE_X(PAGE_WRITE); case DMA1_MASK_REG: if (value & 4) { q_printf("DMA1: mask channel %i\n", value & 3); dma[DMA1].mask |= 1 << (value & 3); } else { q_printf("DMA1: unmask channel %i\n", value & 3); dma[DMA1].mask &= ~(1 << (value & 3)); dma[DMA1].status &= ~(1 << (value & 3)); } break; case DMA2_MASK_REG: if (value & 4) { q_printf("DMA2: mask channel %i\n", value & 3); dma[DMA2].mask |= 1 << (value & 3); } else { q_printf("DMA2: unmask channel %i\n", value & 3); dma[DMA2].mask &= ~(1 << (value & 3)); dma[DMA2].status &= ~(1 << (value & 3)); } break; case DMA1_MODE_REG: dma[DMA1].chans[value & 3].mode = value >> 2; q_printf("DMA1: Write mode 0x%x to Channel %u\n", value >> 2, value & 3); break; case DMA2_MODE_REG: dma[DMA2].chans[value & 3].mode = value >> 2; q_printf("DMA2: Write mode 0x%x to Channel %u\n", value >> 2, value & 3); break; case DMA1_CMD_REG: dma[DMA1].command = value; q_printf("DMA1: Write 0x%x to Command reg\n", value); break; case DMA2_CMD_REG: dma[DMA2].command = value; q_printf("DMA2: Write 0x%x to Command reg\n", value); break; case DMA1_CLEAR_FF_REG: q_printf("DMA1: Clearing Output Flip-Flop\n"); dma[DMA1].ff = 0; break; case DMA2_CLEAR_FF_REG: q_printf("DMA2: Clearing Output Flip-Flop\n"); dma[DMA2].ff = 0; break; case DMA1_RESET_REG: q_printf("DMA1: Reset\n"); dma_soft_reset(DMA1); break; case DMA2_RESET_REG: q_printf("DMA2: Reset\n"); dma_soft_reset(DMA2); break; case DMA1_REQ_REG: if (value & 4) { q_printf("DMA1: Setting request state %#x\n", value); dma[DMA1].request |= 1 << (value & 3); } else { q_printf("DMA1: Clearing request state %#x\n", value); dma[DMA1].request &= ~(1 << (value & 3)); } break; case DMA2_REQ_REG: if (value & 4) { q_printf("DMA2: Setting request state %#x\n", value); dma[DMA2].request |= 1 << (value & 3); } else { q_printf("DMA2: Clearing request state %#x\n", value); dma[DMA2].request &= ~(1 << (value & 3)); } break; case DMA1_CLR_MASK_REG: q_printf("DMA1: Clearing masks\n"); dma[DMA1].mask = 0; dma[DMA1].status &= 0xf0; break; case DMA2_CLR_MASK_REG: q_printf("DMA2: Clearing masks\n"); dma[DMA2].mask = 0; dma[DMA2].status &= 0xf0; break; case DMA1_MASK_ALL_REG: q_printf("DMA1: Setting masks %#x\n", value); dma[DMA1].mask = value; dma[DMA1].status &= 0xf0; break; case DMA2_MASK_ALL_REG: q_printf("DMA2: Setting masks %#x\n", value); dma[DMA2].mask = value; dma[DMA2].status &= 0xf0; break; default: q_printf("DMA: Unhandled Write on 0x%04x\n", (Bit16u) port); } dma_process(); // Not needed in fact }
static Bit8u dma_io_read(ioport_t port) { Bit8u r = 0xff; switch (port) { #define HANDLE_CUR_ADDR_READ(d_n, c_n) \ case DMA##d_n##_ADDR_##c_n: \ r = dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff]; \ q_printf("DMA%i: cur_addr read: %#x from Channel %d byte %d\n", \ d_n, r, d(c_n), dma[d(d_n)].ff); \ dma[d(d_n)].ff ^= 1; \ break HANDLE_X(CUR_ADDR_READ); #define HANDLE_CUR_CNT_READ(d_n, c_n) \ case DMA##d_n##_CNT_##c_n: \ r = dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff]; \ q_printf("DMA%i: cur_cnt read: %#x from Channel %d byte %d\n", \ d_n, r, d(c_n), dma[d(d_n)].ff); \ dma[d(d_n)].ff ^= 1; \ break HANDLE_X(CUR_CNT_READ); #define HANDLE_PAGE_READ(d_n, c_n) \ case DMA##d_n##_PAGE_##c_n: \ r = dma[d(d_n)].chans[d(c_n)].page; \ q_printf("DMA%i: page read: %#x from Channel %d\n", \ d_n, r, d(c_n)); \ break HANDLE_X(PAGE_READ); case DMA1_STAT_REG: r = dma[DMA1].status; q_printf("DMA1: Read %u from Status reg\n", r); dma[DMA1].status &= 0xf0; /* clear status bits */ break; case DMA2_STAT_REG: r = dma[DMA2].status; q_printf("DMA2: Read %u from Status reg\n", r); dma[DMA2].status &= 0xf0; /* clear status bits */ break; case DMA1_TEMP_REG: r = dma[DMA1].tmp_reg; q_printf("DMA1: Read %u from temporary register unimplemented\n", r); break; case DMA2_TEMP_REG: r = dma[DMA2].tmp_reg; q_printf("DMA2: Read %u from temporary register unimplemented\n", r); break; default: q_printf("DMA: Unhandled Read on 0x%04x\n", (Bit16u) port); } dma_process(); // Not needed in fact return r; }
int main(int argc, char *argv[]) { /* test harness */ int tests_passed = 0; int tests_failed = 0; /* create a queue with a size hint */ printf("Creating queue\n"); queue qp = q_create(20); /* how do we see if queue was propery initialized? */ /* add and remove one element */ int e1 = 42; q_add(qp, e1); printf("Test 1: "); q_printf(qp); printf("\n"); /* length should have gone up by one */ if ( q_length(qp) != 1 ) { printf("Test 1 failed, length %d should be 1\n", q_length(qp)); tests_failed++; } else { printf("Test 1 passed.\n"); tests_passed++; } printf("Test 2: "); int e2 = q_remove(qp); q_printf(qp); printf("\n"); if ( q_length(qp) != 0 ) { printf("Test 2.1 failed, length %d should be 0\n", q_length(qp)); tests_failed++; } else { printf("Test 2.1 passed.\n"); tests_passed++; } if ( e1 != e2 ) { printf("Test 2.2 failed, e2 %d should equal e1 %d\n", e2, e1); tests_failed++; } else { printf("Test 2.2 passed.\n"); tests_passed++; } printf("Test 3: "); for (int i=1; i <= 10; i++) { q_add(qp, i); } q_printf(qp); printf("\n"); for (int i=1; i<= 10; i++) { e1 = q_remove(qp); if ( q_length(qp) != 10-i ) { printf("Test 3.1 failed, length %d should be %d\n", q_length(qp), 10-i); tests_failed++; } else { tests_passed++; } if ( e1 != i ) { printf("Test 3.2 failed, element %d should be %d\n", e1, i); tests_failed++; } else { tests_passed++; } } printf("Test 4: "); for (int i=1; i <= 10; i++) { q_add(qp, i); } q_printf(qp); printf("\n"); for (int i=0; i < 10; i++) { int expected = i + 1; int actual = q_get_item(qp, i); if(expected != actual) { printf("Test 4 failed, element #%d should be %d but was %d\n", i, expected, actual); tests_failed++; } else { tests_passed++; } } // Reset to empty for (int i=1; i <= 10; i++) { q_remove(qp); } q_add(qp, e1); printf("Test 5.1: "); q_printf(qp); printf("\n"); /* length should have gone up by one */ if ( q_length(qp) != 1 ) { printf("Test 5.1 failed, length %d should be 1 before deletion\n", q_length(qp)); tests_failed++; } else { int actual = q_delete_item(qp, 0); if( q_length(qp) != 0) { printf("Test 5.1 failed, length %d should be 0 after deletion\n", q_length(qp)); tests_failed++; } else if(actual != e1) { printf("Test 5.1 failed, element retrieved from deleted: Expected: %d; Actual: %d\n", e1, actual); tests_failed++; } else { printf("Test 5.1 passed.\n"); tests_passed++; } } printf("Test 5.2: "); for (int i=1; i <= 10; i++) { q_add(qp, i); } q_printf(qp); printf("\n"); int deletedElement; deletedElement = q_delete_item(qp, 4); if(deletedElement != 5) { printf("Test 5.2 failed, element retrieved from deleted: Expected: 5; Actual: %d\n", deletedElement); tests_failed++; } deletedElement = q_delete_item(qp, 4); if(deletedElement != 6) { printf("Test 5.2 failed, element retrieved from deleted: Expected: 6; Actual: %d\n", deletedElement); tests_failed++; } q_printf(qp); printf("\n"); if( q_length(qp) != 8) { printf("Test 5.2 failed, length %d should be 8 after deletion\n", q_length(qp)); tests_failed++; } else { if(q_get_item(qp, 4) != 7) { printf("Test 5.2 failed, value of element at index 4 after deletion: Expected: 7; Actual: %d\n", q_get_item(qp, 4)); tests_failed++; } else { printf("Test 5.2 passed.\n"); tests_passed++; } } /* a fatal test */ if ( 0 ) { printf("Test 4: remove on empty queue\n"); e2 = q_remove(qp); tests_failed++; } printf("Tests Passed: %d\n", tests_passed); printf("Tests Failed: %d\n", tests_failed); }