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 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  			}