Mon, 06 Dec 2010 01:26:37 +0000
disc dma seems to work, but still no boot ;(
src/main.c | file | annotate | diff | revisions | |
src/memory.c | file | annotate | diff | revisions | |
src/state.h | file | annotate | diff | revisions | |
src/wd279x.c | file | annotate | diff | revisions |
1.1 diff -r a350dfa92895 -r e1693c4b8a0c src/main.c 1.2 --- a/src/main.c Sun Dec 05 16:20:00 2010 +0000 1.3 +++ b/src/main.c Mon Dec 06 01:26:37 2010 +0000 1.4 @@ -208,7 +208,68 @@ 1.5 // 41667 cycles per timeslot. 1.6 clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY); 1.7 1.8 - // TODO: run DMA here 1.9 + // Run the DMA engine 1.10 + // 1.11 + if (state.dmaen) { //((state.dma_count < 0x3fff) && state.dmaen) { 1.12 + printf("DMA: copy addr=%08X count=%08X idmarw=%d dmarw=%d\n", state.dma_address, state.dma_count, state.idmarw, state.dma_reading); 1.13 + if (state.dmaenb) { 1.14 + state.dmaenb = false; 1.15 +// state.dma_address++; 1.16 + state.dma_count++; 1.17 + } 1.18 + // DMA ready to go -- so do it. 1.19 + size_t num = 0; 1.20 + while (state.dma_count < 0x4000) { 1.21 + uint16_t d = 0; 1.22 + 1.23 + // num tells us how many words we've copied. If this is greater than the per-timeslot DMA maximum, bail out! 1.24 + if (num > (1e6/TIMESLOT_FREQUENCY)) break; 1.25 + 1.26 + // Evidently we have more words to copy. Copy them. 1.27 + if (!wd2797_get_drq(&state.fdc_ctx)) { 1.28 + printf("\tDMABAIL: no data! dmac=%04X dmaa=%04X\n", state.dma_count, state.dma_address); 1.29 + // Bail out, no data available. Try again later. 1.30 + // TODO: handle HDD controller too 1.31 + break; 1.32 + } 1.33 + 1.34 + if (!state.dma_reading) { 1.35 + // Data available. Get it from the FDC. 1.36 + d = wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA); 1.37 + d <<= 8; 1.38 + d += wd2797_read_reg(&state.fdc_ctx, WD2797_REG_DATA); 1.39 + 1.40 + // TODO: FIXME: if we get a pagefault, it NEEDS to be tagged as 'peripheral sourced'... this is a HACK! 1.41 + m68k_write_memory_16(state.dma_address << 1, d); 1.42 + } else { 1.43 + // Data write to FDC 1.44 + // TODO: FIXME: if we get a pagefault, it NEEDS to be tagged as 'peripheral sourced'... this is a HACK! 1.45 + d = m68k_read_memory_16(state.dma_address << 1); 1.46 + 1.47 + wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d >> 8)); 1.48 + wd2797_write_reg(&state.fdc_ctx, WD2797_REG_DATA, (d & 0xff)); 1.49 + } 1.50 + 1.51 + // Increment DMA address 1.52 + state.dma_address++; 1.53 + // Increment number of words transferred 1.54 + num++; state.dma_count++; 1.55 + } 1.56 + 1.57 + // Turn off DMA engine if we finished this cycle 1.58 + if (state.dma_count >= 0x4000) { 1.59 + printf("\tDMATRAN: transfer complete! dmaa=%06X, dmac=%04X\n", state.dma_address, state.dma_count); 1.60 + state.dma_count = 0; 1.61 + state.dmaen = false; 1.62 + } 1.63 + } 1.64 + 1.65 + // Any interrupts? 1.66 + if (wd2797_get_irq(&state.fdc_ctx)) { 1.67 + m68k_set_irq(2); 1.68 + } else { 1.69 + m68k_set_irq(0); 1.70 + } 1.71 1.72 // Is it time to run the 60Hz periodic interrupt yet? 1.73 if (clock_cycles > CLOCKS_PER_60HZ) {
2.1 diff -r a350dfa92895 -r e1693c4b8a0c src/memory.c 2.2 --- a/src/memory.c Sun Dec 05 16:20:00 2010 +0000 2.3 +++ b/src/memory.c Mon Dec 06 01:26:37 2010 +0000 2.4 @@ -238,8 +238,13 @@ 2.5 case 0x050000: // Phone status 2.6 break; 2.7 case 0x060000: // DMA Count 2.8 + // U/OERR- is always inactive (bit set) 2.9 + data = (state.dma_count & 0x3fff) | 0x8000; 2.10 + handled = true; 2.11 break; 2.12 case 0x070000: // Line Printer Status Register 2.13 + data = 0x00120012; // no parity error, no line printer error, no irqs from FDD or HDD 2.14 + data |= (state.fdc_ctx.irql) ? 0x00080008 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this 2.15 break; 2.16 case 0x080000: // Real Time Clock 2.17 break; 2.18 @@ -311,7 +316,7 @@ 2.19 break; 2.20 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.21 data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); 2.22 - printf("WD279X: rd %02X ==> %02X\n", (address >> 1) & 3, data); 2.23 + printf("WD279X: rd32 %02X ==> %02X\n", (address >> 1) & 3, data); 2.24 handled = true; 2.25 break; 2.26 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.27 @@ -403,8 +408,13 @@ 2.28 case 0x050000: // Phone status 2.29 break; 2.30 case 0x060000: // DMA Count 2.31 + // U/OERR- is always inactive (bit set) 2.32 + data = (state.dma_count & 0x3fff) | 0x8000; 2.33 + handled = true; 2.34 break; 2.35 case 0x070000: // Line Printer Status Register 2.36 + data = 0x0012; // no parity error, no line printer error, no irqs from FDD or HDD 2.37 + data |= (state.fdc_ctx.irql) ? 0x0008 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this 2.38 break; 2.39 case 0x080000: // Real Time Clock 2.40 break; 2.41 @@ -476,7 +486,7 @@ 2.42 break; 2.43 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.44 data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); 2.45 - printf("WD279X: rd %02X ==> %02X\n", (address >> 1) & 3, data); 2.46 + printf("WD279X: rd16 %02X ==> %02X\n", (address >> 1) & 3, data); 2.47 handled = true; 2.48 break; 2.49 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.50 @@ -577,8 +587,16 @@ 2.51 case 0x050000: // Phone status 2.52 break; 2.53 case 0x060000: // DMA Count 2.54 + // TODO: how to handle this in 8bit mode? 2.55 break; 2.56 case 0x070000: // Line Printer Status Register 2.57 + printf("\tLPSR RD8 fdc irql=%d, irqe=%d\n", state.fdc_ctx.irql, state.fdc_ctx.irqe); 2.58 + if (address & 1) { 2.59 + data = 0x12; // no parity error, no line printer error, no irqs from FDD or HDD 2.60 + data |= (state.fdc_ctx.irql) ? 0x08 : 0; // FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this 2.61 + } else { 2.62 + data = 0; 2.63 + } 2.64 break; 2.65 case 0x080000: // Real Time Clock 2.66 break; 2.67 @@ -650,7 +668,7 @@ 2.68 break; 2.69 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.70 data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3); 2.71 - printf("WD279X: rd %02X ==> %02X\n", (address >> 1) & 3, data); 2.72 + printf("WD279X: rd8 %02X ==> %02X\n", (address >> 1) & 3, data); 2.73 handled = true; 2.74 break; 2.75 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.76 @@ -736,6 +754,13 @@ 2.77 case 0x050000: // Phone status 2.78 break; 2.79 case 0x060000: // DMA Count 2.80 + printf("WR32 dmacount %08X\n", value); 2.81 + state.dma_count = (value & 0x3FFF); 2.82 + state.idmarw = ((value & 0x4000) == 0x4000); 2.83 + state.dmaen = ((value & 0x8000) == 0x8000); 2.84 + state.dmaenb = state.dmaen; 2.85 + printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen); 2.86 + handled = true; 2.87 break; 2.88 case 0x070000: // Line Printer Status Register 2.89 break; 2.90 @@ -797,6 +822,8 @@ 2.91 // A14 low -- set least significant bits 2.92 state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); 2.93 } 2.94 + printf("WR DMA_ADDR, now %08X\n", state.dma_address); 2.95 + handled = true; 2.96 break; 2.97 case 0x0E0000: // Disk Control Register 2.98 // B7 = FDD controller reset 2.99 @@ -806,6 +833,7 @@ 2.100 // B4 = HDD controller reset -- TODO 2.101 // B3 = HDD0 select -- TODO 2.102 // B2,1,0 = HDD0 head select 2.103 + handled = true; 2.104 break; 2.105 case 0x0F0000: // Line Printer Data Register 2.106 break; 2.107 @@ -835,9 +863,9 @@ 2.108 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller 2.109 break; 2.110 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.111 + printf("WD279X: wr32 %02X ==> %02X\n", (address >> 1) & 3, value); 2.112 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); 2.113 - printf("WD279X: wr %02X ==> %02X\n\t", (address >> 1) & 3, value); 2.114 - //handled = true; 2.115 + handled = true; 2.116 break; 2.117 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.118 break; 2.119 @@ -929,6 +957,13 @@ 2.120 case 0x050000: // Phone status 2.121 break; 2.122 case 0x060000: // DMA Count 2.123 + printf("WR16 dmacount %08X\n", value); 2.124 + state.dma_count = (value & 0x3FFF); 2.125 + state.idmarw = ((value & 0x4000) == 0x4000); 2.126 + state.dmaen = ((value & 0x8000) == 0x8000); 2.127 + state.dmaenb = state.dmaen; 2.128 + printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen); 2.129 + handled = true; 2.130 break; 2.131 case 0x070000: // Line Printer Status Register 2.132 break; 2.133 @@ -990,6 +1025,8 @@ 2.134 // A14 low -- set least significant bits 2.135 state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); 2.136 } 2.137 + printf("WR DMA_ADDR, now %08X\n", state.dma_address); 2.138 + handled = true; 2.139 break; 2.140 case 0x0E0000: // Disk Control Register 2.141 // B7 = FDD controller reset 2.142 @@ -999,6 +1036,7 @@ 2.143 // B4 = HDD controller reset -- TODO 2.144 // B3 = HDD0 select -- TODO 2.145 // B2,1,0 = HDD0 head select 2.146 + handled = true; 2.147 break; 2.148 case 0x0F0000: // Line Printer Data Register 2.149 break; 2.150 @@ -1027,9 +1065,9 @@ 2.151 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller 2.152 break; 2.153 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.154 + printf("WD279X: wr16 %02X ==> %02X\n", (address >> 1) & 3, value); 2.155 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); 2.156 - printf("WD279X: wr %02X ==> %02X\n\t", (address >> 1) & 3, value); 2.157 - //handled = true; 2.158 + handled = true; 2.159 break; 2.160 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.161 break; 2.162 @@ -1121,6 +1159,7 @@ 2.163 case 0x050000: // Phone status 2.164 break; 2.165 case 0x060000: // DMA Count 2.166 + // TODO: how to handle this in 8bit mode? 2.167 break; 2.168 case 0x070000: // Line Printer Status Register 2.169 break; 2.170 @@ -1155,6 +1194,8 @@ 2.171 } 2.172 break; 2.173 case 0x0A0000: // Miscellaneous Control Register 2.174 + // TODO: how to handle this in 8bit mode? 2.175 +/* 2.176 // TODO: handle the ctrl bits properly 2.177 if ((address & 1) == 0) { 2.178 // low byte 2.179 @@ -1170,6 +1211,7 @@ 2.180 (state.leds & 2) ? "Y" : "-", 2.181 (state.leds & 1) ? "R" : "-"); 2.182 handled = true; 2.183 +*/ 2.184 break; 2.185 case 0x0B0000: // TM/DIALWR 2.186 break; 2.187 @@ -1187,6 +1229,8 @@ 2.188 // A14 low -- set least significant bits 2.189 state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff); 2.190 } 2.191 + printf("WR DMA_ADDR, now %08X\n", state.dma_address); 2.192 + handled = true; 2.193 break; 2.194 case 0x0E0000: // Disk Control Register 2.195 // B7 = FDD controller reset 2.196 @@ -1196,6 +1240,7 @@ 2.197 // B4 = HDD controller reset -- TODO 2.198 // B3 = HDD0 select -- TODO 2.199 // B2,1,0 = HDD0 head select 2.200 + handled = true; 2.201 break; 2.202 case 0x0F0000: // Line Printer Data Register 2.203 break; 2.204 @@ -1224,9 +1269,9 @@ 2.205 case 0x000000: // [ef][08]xxxx ==> WD1010 hard disc controller 2.206 break; 2.207 case 0x010000: // [ef][19]xxxx ==> WD2797 floppy disc controller 2.208 + printf("WD279X: wr8 %02X ==> %02X\n", (address >> 1) & 3, value); 2.209 wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value); 2.210 - printf("WD279X: wr %02X ==> %02X\n\t", (address >> 1) & 3, value); 2.211 - //handled = true; 2.212 + handled = true; 2.213 break; 2.214 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.215 break;
3.1 diff -r a350dfa92895 -r e1693c4b8a0c src/state.h 3.2 --- a/src/state.h Sun Dec 05 16:20:00 2010 +0000 3.3 +++ b/src/state.h Mon Dec 06 01:26:37 2010 +0000 3.4 @@ -47,6 +47,15 @@ 3.5 /// DMA Address Register 3.6 uint32_t dma_address; 3.7 3.8 + /// DMA count 3.9 + uint32_t dma_count; 3.10 + 3.11 + /// DMA direction 3.12 + bool idmarw; 3.13 + /// DMA enable 3.14 + bool dmaen; 3.15 + bool dmaenb; 3.16 + 3.17 /// Floppy disc controller context 3.18 WD2797_CTX fdc_ctx; 3.19 } S_state;
4.1 diff -r a350dfa92895 -r e1693c4b8a0c src/wd279x.c 4.2 --- a/src/wd279x.c Sun Dec 05 16:20:00 2010 +0000 4.3 +++ b/src/wd279x.c Mon Dec 06 01:26:37 2010 +0000 4.4 @@ -1,6 +1,7 @@ 4.5 #include <stdint.h> 4.6 #include <stdbool.h> 4.7 #include <malloc.h> 4.8 +#include "musashi/m68k.h" 4.9 #include "wd279x.h" 4.10 4.11 /// WD2797 command constants 4.12 @@ -164,12 +165,17 @@ 4.13 case WD2797_REG_STATUS: // Status register 4.14 // Read from status register clears IRQ 4.15 ctx->irql = false; 4.16 + ctx->irqe = false; 4.17 4.18 // Get current status flags (set by last command) 4.19 - temp = ctx->status; 4.20 // DRQ bit 4.21 - if (ctx->cmd_has_drq) 4.22 + if (ctx->cmd_has_drq) { 4.23 + printf("\tWDFDC rd sr, has drq, pos=%lu len=%lu\n", ctx->data_pos, ctx->data_len); 4.24 + temp = ctx->status & ~0x03; 4.25 temp |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 4.26 + } else { 4.27 + temp = ctx->status & ~0x01; 4.28 + } 4.29 // FDC is busy if there is still data in the buffer 4.30 temp |= (ctx->data_pos < ctx->data_len) ? 0x01 : 0x00; // if data in buffer, then DMA hasn't copied it yet, and we're still busy! 4.31 // TODO: also if seek delay / read delay hasn't passed (but that's for later) 4.32 @@ -184,9 +190,16 @@ 4.33 case WD2797_REG_DATA: // Data register 4.34 // If there's data in the buffer, return it. Otherwise return 0xFF. 4.35 if (ctx->data_pos < ctx->data_len) { 4.36 + // set IRQ if this is the last data byte 4.37 + if (ctx->data_pos == (ctx->data_len-1)) { 4.38 + // Set IRQ only if IRQL has been cleared (no pending IRQs) 4.39 + ctx->irqe = ctx->irql ? ctx->irqe : true; 4.40 + ctx->irql = true; 4.41 + } 4.42 // return data byte and increment pointer 4.43 return ctx->data[ctx->data_pos++]; 4.44 } else { 4.45 + // command finished 4.46 return 0xff; 4.47 } 4.48 4.49 @@ -205,6 +218,8 @@ 4.50 bool is_type1 = false; 4.51 int temp; 4.52 4.53 + m68k_end_timeslice(); 4.54 + 4.55 switch (addr) { 4.56 case WD2797_REG_COMMAND: // Command register 4.57 // write to command register clears interrupt request 4.58 @@ -300,13 +315,16 @@ 4.59 // TODO: Set a timer for seeks, and ONLY clear BUSY when that timer expires. Need periodics for that. 4.60 4.61 // Set IRQ only if IRQL has been cleared (no pending IRQs) 4.62 - ctx->irqe = !ctx->irql; 4.63 + ctx->irqe = ctx->irql ? ctx->irqe : true; 4.64 ctx->irql = true; 4.65 return; 4.66 } 4.67 4.68 // That's the Type 1 (seek) commands sorted. Now for the others. 4.69 4.70 + // All these commands return the DRQ bit... 4.71 + ctx->cmd_has_drq = true; 4.72 + 4.73 // If drive isn't ready, then set status B7 and exit 4.74 if (ctx->disc_image == NULL) { 4.75 ctx->status = 0x80; 4.76 @@ -322,7 +340,7 @@ 4.77 ctx->status = 0x40; 4.78 4.79 // Set IRQ only if IRQL has been cleared (no pending IRQs) 4.80 - ctx->irqe = !ctx->irql; 4.81 + ctx->irqe = ctx->irql ? ctx->irqe : true; 4.82 ctx->irql = true; 4.83 4.84 return; 4.85 @@ -351,6 +369,7 @@ 4.86 ctx->data[ctx->data_len++] = 0; // TODO: IDAM CRC! 4.87 ctx->data[ctx->data_len++] = 0; 4.88 4.89 + ctx->status = 0; 4.90 // B6, B5 = 0 4.91 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated 4.92 // B3 = CRC Error. Not possible. 4.93 @@ -361,6 +380,7 @@ 4.94 4.95 case CMD_READ_SECTOR: 4.96 case CMD_READ_SECTOR_MULTI: 4.97 + printf("WD279X: READ SECTOR chs=%d:%d:%d\n", ctx->track, ctx->head, ctx->sector); 4.98 // Read Sector or Read Sector Multiple 4.99 // reset data pointers 4.100 ctx->data_pos = ctx->data_len = 0; 4.101 @@ -374,13 +394,16 @@ 4.102 for (int i=0; i<temp; i++) { 4.103 // Calculate the LBA address of the required sector 4.104 lba = ((((ctx->track * ctx->geom_heads) + ctx->head) * ctx->geom_spt) + ((ctx->sector + i - 1) % ctx->geom_spt)) * ctx->geom_secsz; 4.105 + printf("\tREAD lba = %lu\n", lba); 4.106 4.107 // Read the sector from the file 4.108 fseek(ctx->disc_image, lba, SEEK_SET); 4.109 ctx->data_len += fread(&ctx->data[ctx->data_len], 1, ctx->geom_secsz, ctx->disc_image); 4.110 + printf("\tREAD len=%lu, pos=%lu, ssz=%d\n", ctx->data_len, ctx->data_pos, ctx->geom_secsz); 4.111 // TODO: check fread return value! if < secsz, BAIL! (call it a crc error or secnotfound maybe? also log to stderr) 4.112 } 4.113 4.114 + ctx->status = 0; 4.115 // B6 = 0 4.116 // B5 = Record Type -- 1 = deleted, 0 = normal. We can't emulate anything but normal data blocks. 4.117 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated 4.118 @@ -393,6 +416,7 @@ 4.119 case CMD_READ_TRACK: 4.120 // Read Track 4.121 // TODO! implement this 4.122 + ctx->status = 0; 4.123 // B6, B5, B4, B3 = 0 4.124 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 4.125 // B1 = DRQ. Data request. 4.126 @@ -408,6 +432,7 @@ 4.127 4.128 // TODO: set "write pending" flag, and write LBA, and go from there. 4.129 4.130 + ctx->status = 0; 4.131 // B6 = Write Protect. FIXME -- emulate this! 4.132 // B5 = 0 4.133 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated 4.134 @@ -419,6 +444,7 @@ 4.135 4.136 case CMD_FORMAT_TRACK: 4.137 // Write Track (aka Format Track) 4.138 + ctx->status = 0; 4.139 // B6 = Write Protect. FIXME -- emulate this! 4.140 // B5, B4, B3 = 0 4.141 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 4.142 @@ -430,9 +456,10 @@ 4.143 // Force Interrupt... 4.144 // Terminates current operation and sends an interrupt 4.145 // TODO! 4.146 + ctx->status = 0; 4.147 ctx->data_pos = ctx->data_len = 0; 4.148 // Set IRQ only if IRQL has been cleared (no pending IRQs) 4.149 - ctx->irqe = !ctx->irql; 4.150 + ctx->irqe = ctx->irql ? ctx->irqe : true; 4.151 ctx->irql = true; 4.152 break; 4.153 } 4.154 @@ -453,6 +480,13 @@ 4.155 // If we're processing a write command, and there's space in the 4.156 // buffer, allow the write. 4.157 if (ctx->data_pos < ctx->data_len) { 4.158 + // set IRQ if this is the last data byte 4.159 + if (ctx->data_pos == (ctx->data_len-1)) { 4.160 + // Set IRQ only if IRQL has been cleared (no pending IRQs) 4.161 + ctx->irqe = ctx->irql ? ctx->irqe : true; 4.162 + ctx->irql = true; 4.163 + } 4.164 + 4.165 // store data byte and increment pointer 4.166 ctx->data[ctx->data_pos++] = val; 4.167 }