src/wd279x.c

changeset 111
4c85846b09cd
parent 79
674226015c8a
     1.1 --- a/src/wd279x.c	Thu Dec 08 23:44:19 2011 +0000
     1.2 +++ b/src/wd279x.c	Sat Nov 17 19:13:08 2012 +0000
     1.3 @@ -35,6 +35,7 @@
     1.4  {
     1.5  	// track, head and sector unknown
     1.6  	ctx->track = ctx->head = ctx->sector = 0;
     1.7 +	ctx->track_reg = 0;
     1.8  
     1.9  	// no IRQ pending
    1.10  	ctx->irq = false;
    1.11 @@ -47,6 +48,9 @@
    1.12  	ctx->status = 0;
    1.13  	ctx->cmd_has_drq = false;
    1.14  
    1.15 +	// No format command in progress
    1.16 +	ctx->formatting = false;
    1.17 +
    1.18  	// Clear data register
    1.19  	ctx->data_reg = 0;
    1.20  
    1.21 @@ -63,6 +67,7 @@
    1.22  {
    1.23  	// track, head and sector unknown
    1.24  	ctx->track = ctx->head = ctx->sector = 0;
    1.25 +	ctx->track_reg = 0;
    1.26  
    1.27  	// no IRQ pending
    1.28  	ctx->irq = false;
    1.29 @@ -99,14 +104,13 @@
    1.30  	return ctx->irq;
    1.31  }
    1.32  
    1.33 -
    1.34  bool wd2797_get_drq(WD2797_CTX *ctx)
    1.35  {
    1.36  	return (ctx->data_pos < ctx->data_len);
    1.37  }
    1.38  
    1.39  
    1.40 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
    1.41 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable)
    1.42  {
    1.43  	size_t filesize;
    1.44  
    1.45 @@ -136,7 +140,7 @@
    1.46  	ctx->geom_secsz = secsz;
    1.47  	ctx->geom_heads = heads;
    1.48  	ctx->geom_spt = spt;
    1.49 -
    1.50 +	ctx->writeable = writeable;
    1.51  	return WD2797_ERR_OK;
    1.52  }
    1.53  
    1.54 @@ -160,6 +164,7 @@
    1.55  uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr)
    1.56  {
    1.57  	uint8_t temp = 0;
    1.58 +	m68k_end_timeslice();
    1.59  
    1.60  	switch (addr & 0x03) {
    1.61  		case WD2797_REG_STATUS:		// Status register
    1.62 @@ -176,12 +181,12 @@
    1.63  				temp = ctx->status & ~0x01;
    1.64  			}
    1.65  			// FDC is busy if there is still data in the buffer
    1.66 -			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!
    1.67 +			temp |= (ctx->data_pos < ctx->data_len) ? 0x81 : 0x00;	// if data in buffer, then DMA hasn't copied it yet, and we're still busy!
    1.68  																	// TODO: also if seek delay / read delay hasn't passed (but that's for later)
    1.69  			return temp;
    1.70  
    1.71  		case WD2797_REG_TRACK:		// Track register
    1.72 -			return ctx->track;
    1.73 +			return ctx->track_reg;
    1.74  
    1.75  		case WD2797_REG_SECTOR:		// Sector register
    1.76  			return ctx->sector;
    1.77 @@ -198,7 +203,7 @@
    1.78  				return ctx->data[ctx->data_pos++];
    1.79  			} else {
    1.80  				// command finished
    1.81 -				return 0xff;
    1.82 +				return ctx->data_reg;
    1.83  			}
    1.84  
    1.85  		default:
    1.86 @@ -215,7 +220,6 @@
    1.87  	size_t lba;
    1.88  	bool is_type1 = false;
    1.89  	int temp;
    1.90 -
    1.91  	m68k_end_timeslice();
    1.92  
    1.93  	switch (addr) {
    1.94 @@ -235,14 +239,14 @@
    1.95  				case CMD_RESTORE:
    1.96  					// Restore. Set track to 0 and throw an IRQ.
    1.97  					is_type1 = true;
    1.98 -					ctx->track = 0;
    1.99 +					ctx->track = ctx->track_reg = 0;
   1.100  					break;
   1.101  
   1.102  				case CMD_SEEK:
   1.103  					// Seek. Seek to the track specced in the Data Register.
   1.104  					is_type1 = true;
   1.105  					if (ctx->data_reg < ctx->geom_tracks) {
   1.106 -						ctx->track = ctx->data_reg;
   1.107 +						ctx->track = ctx->track_reg = ctx->data_reg;
   1.108  					} else {
   1.109  						// Seek error. :(
   1.110  						ctx->status = 0x10;
   1.111 @@ -256,26 +260,17 @@
   1.112  
   1.113  				case CMD_STEPIN:
   1.114  				case CMD_STEPOUT:
   1.115 -					// TODO! deal with trk0!
   1.116 -					// Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
   1.117 -					if (cmd == CMD_STEPIN) {
   1.118 -						ctx->last_step_dir = 1;
   1.119 -					} else {
   1.120 -						ctx->last_step_dir = -1;
   1.121 -					}
   1.122 -					is_type1 = true;
   1.123 -					break;
   1.124 -
   1.125  				case CMD_STEP_TU:
   1.126  				case CMD_STEPIN_TU:
   1.127  				case CMD_STEPOUT_TU:
   1.128  					// if this is a Step In or Step Out cmd, set the step-direction
   1.129 -					if (cmd == CMD_STEPIN_TU) {
   1.130 +					if ((cmd & ~0x10) == CMD_STEPIN) {
   1.131  						ctx->last_step_dir = 1;
   1.132 -					} else if (cmd == CMD_STEPOUT_TU) {
   1.133 +					} else if ((cmd & ~0x10) == CMD_STEPOUT) {
   1.134  						ctx->last_step_dir = -1;
   1.135  					}
   1.136  
   1.137 +
   1.138  					// Seek one step in the last direction used.
   1.139  					ctx->track += ctx->last_step_dir;
   1.140  					if (ctx->track < 0) ctx->track = 0;
   1.141 @@ -284,6 +279,10 @@
   1.142  						ctx->status = 0x10;
   1.143  						ctx->track = ctx->geom_tracks - 1;
   1.144  					}
   1.145 +					if (cmd & 0x10){
   1.146 +						ctx->track_reg = ctx->track;
   1.147 +					}
   1.148 +
   1.149  					is_type1 = true;
   1.150  					break;
   1.151  
   1.152 @@ -329,8 +328,7 @@
   1.153  			}
   1.154  
   1.155  			// If this is a Write command, check write protect status too
   1.156 -			// TODO!
   1.157 -			if (false) {
   1.158 +			if (!ctx->writeable) {
   1.159  				// Write protected disc...
   1.160  				if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) {
   1.161  					// Set Write Protect bit and bail.
   1.162 @@ -388,9 +386,9 @@
   1.163  								ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
   1.164  						// CHS parameters exceed limits
   1.165  						ctx->status = 0x10;		// Record Not Found
   1.166 -						break;
   1.167  						// Set IRQ
   1.168  						ctx->irq = true;
   1.169 +						break;
   1.170  					}
   1.171  
   1.172  					// reset data pointers
   1.173 @@ -430,12 +428,14 @@
   1.174  				case CMD_READ_TRACK:
   1.175  					// Read Track
   1.176  					// TODO! implement this
   1.177 -					ctx->head = (val & 0x02) ? 1 : 0;
   1.178 -					ctx->status = 0;
   1.179 +					// ctx->head = (val & 0x02) ? 1 : 0;
   1.180 +					// ctx->status = 0;
   1.181  					// B6, B5, B4, B3 = 0
   1.182  					// B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
   1.183  					// B1 = DRQ. Data request.
   1.184 -					ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   1.185 +					// ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   1.186 +					ctx->irq = true;
   1.187 +					ctx->status = 0x10;
   1.188  					break;
   1.189  
   1.190  				case CMD_WRITE_SECTOR:
   1.191 @@ -444,12 +444,21 @@
   1.192  
   1.193  					ctx->head = (val & 0x02) ? 1 : 0;
   1.194  					// reset data pointers
   1.195 -					ctx->data_pos = ctx->data_len = 0;
   1.196 +					ctx->data_pos = 0;
   1.197  
   1.198 -					// TODO: set "write pending" flag, and write LBA, and go from there.
   1.199 +					// Calculate number of sectors to write to disc
   1.200 +					if (cmd == CMD_WRITE_SECTOR_MULTI)
   1.201 +						/*XXX: is this the correct value?*/
   1.202 +						temp = ctx->geom_spt;
   1.203 +					else
   1.204 +						temp = 1;
   1.205 +					ctx->data_len = temp * ctx->geom_secsz;
   1.206 +
   1.207 +					lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector)) - 1;
   1.208 +					ctx->write_pos = lba * ctx->geom_secsz;
   1.209  
   1.210  					ctx->status = 0;
   1.211 -					// B6 = Write Protect. FIXME -- emulate this!
   1.212 +					// B6 = Write Protect. This would have been set earlier.
   1.213  					// B5 = 0
   1.214  					// B4 = Record Not Found. We're not going to see this... FIXME-not emulated
   1.215  					// B3 = CRC Error. Not possible.
   1.216 @@ -465,24 +474,35 @@
   1.217  					// B6 = Write Protect. FIXME -- emulate this!
   1.218  					// B5, B4, B3 = 0
   1.219  					// B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
   1.220 +					ctx->data_pos = 0;
   1.221 +					ctx->data_len = 7170;
   1.222  					// B1 = DRQ. Data request.
   1.223  					ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   1.224 +					ctx->formatting = true;
   1.225  					break;
   1.226  
   1.227  				case CMD_FORCE_INTERRUPT:
   1.228  					// Force Interrupt...
   1.229  					// Terminates current operation and sends an interrupt
   1.230  					// TODO!
   1.231 -					ctx->status = 0;
   1.232 +					ctx->status = 0x20;
   1.233 +					if (!ctx->writeable){
   1.234 +						ctx->status |= 0x40;
   1.235 +					}
   1.236 +					if (ctx->track == 0){
   1.237 +						ctx->status = 0x04;
   1.238 +					}
   1.239  					ctx->data_pos = ctx->data_len = 0;
   1.240 -					// Set IRQ
   1.241 -					ctx->irq = true;
   1.242 +					if (cmd & 8){
   1.243 +						// Set IRQ
   1.244 +						ctx->irq = true;
   1.245 +					}
   1.246  					break;
   1.247  			}
   1.248  			break;
   1.249  
   1.250  		case WD2797_REG_TRACK:		// Track register
   1.251 -			ctx->track = val;
   1.252 +			ctx->track = ctx->track_reg = val;
   1.253  			break;
   1.254  
   1.255  		case WD2797_REG_SECTOR:		// Sector register
   1.256 @@ -492,20 +512,35 @@
   1.257  		case WD2797_REG_DATA:		// Data register
   1.258  			// Save the value written into the data register
   1.259  			ctx->data_reg = val;
   1.260 -
   1.261  			// If we're processing a write command, and there's space in the
   1.262  			// buffer, allow the write.
   1.263 -			if (ctx->data_pos < ctx->data_len) {
   1.264 -				// set IRQ if this is the last data byte
   1.265 -				if (ctx->data_pos == (ctx->data_len-1)) {
   1.266 -					// Set IRQ
   1.267 +			if (ctx->data_pos < ctx->data_len && (ctx->write_pos >= 0 || ctx->formatting)) {
   1.268 +				if (!ctx->formatting) ctx->data[ctx->data_pos] = val;
   1.269 +				// store data byte and increment pointer
   1.270 +				ctx->data_pos++;
   1.271 +
   1.272 +				// set IRQ and write data if this is the last data byte
   1.273 +				if (ctx->data_pos == ctx->data_len) {
   1.274 +					if (!ctx->formatting){
   1.275 +						fseek(ctx->disc_image, ctx->write_pos, SEEK_SET);
   1.276 +						fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image);
   1.277 +						fflush(ctx->disc_image);
   1.278 +					}
   1.279 +					// Set IRQ and reset write pointer
   1.280  					ctx->irq = true;
   1.281 +					ctx->write_pos = -1;
   1.282 +					ctx->formatting = false;
   1.283  				}
   1.284  
   1.285 -				// store data byte and increment pointer
   1.286 -				ctx->data[ctx->data_pos++] = val;
   1.287  			}
   1.288  			break;
   1.289  	}
   1.290  }
   1.291  
   1.292 +void wd2797_dma_miss(WD2797_CTX *ctx)
   1.293 +{
   1.294 +	ctx->data_pos = ctx->data_len;
   1.295 +	ctx->write_pos = 0;
   1.296 +	ctx->status = 4; /* lost data */
   1.297 +	ctx->irq = true;
   1.298 +}