disc dma seems to work, but still no boot ;(

Mon, 06 Dec 2010 01:26:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 06 Dec 2010 01:26:37 +0000
changeset 53
e1693c4b8a0c
parent 52
a350dfa92895
child 54
57c6ef81ae81

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  			}