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