Improve floppy disc support

Sat, 17 Nov 2012 19:13:08 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sat, 17 Nov 2012 19:13:08 +0000
changeset 111
4c85846b09cd
parent 110
acea4b2f396f
child 112
a392eb8f9806

Improve floppy disc support

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-Message-ID: <50A772FC.8020009@gmail.com>

src/main.c file | annotate | diff | revisions
src/wd279x.c file | annotate | diff | revisions
src/wd279x.h file | annotate | diff | revisions
     1.1 --- a/src/main.c	Thu Dec 08 23:44:19 2011 +0000
     1.2 +++ b/src/main.c	Sat Nov 17 19:13:08 2012 +0000
     1.3 @@ -19,6 +19,26 @@
     1.4  	exit(EXIT_FAILURE);
     1.5  }
     1.6  
     1.7 +static int load_fd()
     1.8 +{
     1.9 +
    1.10 +	int writeable = 1;
    1.11 +	state.fdc_disc = fopen("discim", "r+b");
    1.12 +	if (!state.fdc_disc){
    1.13 +		writeable = 0;
    1.14 +		state.fdc_disc = fopen("discim", "rb");
    1.15 +	}
    1.16 +	if (!state.fdc_disc){
    1.17 +		fprintf(stderr, "ERROR loading disc image 'discim'.\n");
    1.18 +		state.fdc_disc = NULL;
    1.19 +		return (0);
    1.20 +	}else{
    1.21 +		wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2, writeable);
    1.22 +		fprintf(stderr, "Disc image loaded.\n");
    1.23 +		return (1);
    1.24 +	}
    1.25 +}
    1.26 +
    1.27  /**
    1.28   * @brief Set the pixel at (x, y) to the given value
    1.29   * @note The surface must be locked before calling this!
    1.30 @@ -140,14 +160,7 @@
    1.31  							state.fdc_disc = NULL;
    1.32  							fprintf(stderr, "Disc image unloaded.\n");
    1.33  						} else {
    1.34 -							state.fdc_disc = fopen("discim", "rb");
    1.35 -							if (!state.fdc_disc) {
    1.36 -								fprintf(stderr, "ERROR loading disc image 'discim'.\n");
    1.37 -								state.fdc_disc = NULL;
    1.38 -							} else {
    1.39 -								wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2);
    1.40 -								fprintf(stderr, "Disc image loaded.\n");
    1.41 -							}
    1.42 +							load_fd();
    1.43  						}
    1.44  						break;
    1.45  					case SDLK_F12:
    1.46 @@ -214,12 +227,7 @@
    1.47  	SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
    1.48  
    1.49  	// Load a disc image
    1.50 -	state.fdc_disc = fopen("discim", "rb");
    1.51 -	if (!state.fdc_disc) {
    1.52 -		fprintf(stderr, "ERROR loading disc image 'discim'.\n");
    1.53 -		return -4;
    1.54 -	}
    1.55 -	wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2);
    1.56 +	load_fd();
    1.57  
    1.58  	/***
    1.59  	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
    1.60 @@ -345,8 +353,11 @@
    1.61  //				state.dma_count = 0;
    1.62  				state.dmaen = false;
    1.63  			}
    1.64 +		}else if (wd2797_get_drq(&state.fdc_ctx)){
    1.65 +			wd2797_dma_miss(&state.fdc_ctx);
    1.66  		}
    1.67  
    1.68 +
    1.69  		// Any interrupts? --> TODO: masking
    1.70  /*		if (!lastirq_fdc) {
    1.71  			if (wd2797_get_irq(&state.fdc_ctx)) {
    1.72 @@ -354,12 +365,13 @@
    1.73  				m68k_set_irq(2);
    1.74  			}
    1.75  */
    1.76 -		if (keyboard_get_irq(&state.kbd)) {
    1.77 +		if (wd2797_get_irq(&state.fdc_ctx)){
    1.78 +			m68k_set_irq(2);
    1.79 +		}else if (keyboard_get_irq(&state.kbd)) {
    1.80  			m68k_set_irq(3);
    1.81  		} else {
    1.82 -			lastirq_fdc = wd2797_get_irq(&state.fdc_ctx);
    1.83  //			if (!state.timer_asserted){
    1.84 -//				m68k_set_irq(0);
    1.85 +				m68k_set_irq(0);
    1.86  //			}
    1.87  		}
    1.88  
     2.1 --- a/src/wd279x.c	Thu Dec 08 23:44:19 2011 +0000
     2.2 +++ b/src/wd279x.c	Sat Nov 17 19:13:08 2012 +0000
     2.3 @@ -35,6 +35,7 @@
     2.4  {
     2.5  	// track, head and sector unknown
     2.6  	ctx->track = ctx->head = ctx->sector = 0;
     2.7 +	ctx->track_reg = 0;
     2.8  
     2.9  	// no IRQ pending
    2.10  	ctx->irq = false;
    2.11 @@ -47,6 +48,9 @@
    2.12  	ctx->status = 0;
    2.13  	ctx->cmd_has_drq = false;
    2.14  
    2.15 +	// No format command in progress
    2.16 +	ctx->formatting = false;
    2.17 +
    2.18  	// Clear data register
    2.19  	ctx->data_reg = 0;
    2.20  
    2.21 @@ -63,6 +67,7 @@
    2.22  {
    2.23  	// track, head and sector unknown
    2.24  	ctx->track = ctx->head = ctx->sector = 0;
    2.25 +	ctx->track_reg = 0;
    2.26  
    2.27  	// no IRQ pending
    2.28  	ctx->irq = false;
    2.29 @@ -99,14 +104,13 @@
    2.30  	return ctx->irq;
    2.31  }
    2.32  
    2.33 -
    2.34  bool wd2797_get_drq(WD2797_CTX *ctx)
    2.35  {
    2.36  	return (ctx->data_pos < ctx->data_len);
    2.37  }
    2.38  
    2.39  
    2.40 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
    2.41 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable)
    2.42  {
    2.43  	size_t filesize;
    2.44  
    2.45 @@ -136,7 +140,7 @@
    2.46  	ctx->geom_secsz = secsz;
    2.47  	ctx->geom_heads = heads;
    2.48  	ctx->geom_spt = spt;
    2.49 -
    2.50 +	ctx->writeable = writeable;
    2.51  	return WD2797_ERR_OK;
    2.52  }
    2.53  
    2.54 @@ -160,6 +164,7 @@
    2.55  uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr)
    2.56  {
    2.57  	uint8_t temp = 0;
    2.58 +	m68k_end_timeslice();
    2.59  
    2.60  	switch (addr & 0x03) {
    2.61  		case WD2797_REG_STATUS:		// Status register
    2.62 @@ -176,12 +181,12 @@
    2.63  				temp = ctx->status & ~0x01;
    2.64  			}
    2.65  			// FDC is busy if there is still data in the buffer
    2.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!
    2.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!
    2.68  																	// TODO: also if seek delay / read delay hasn't passed (but that's for later)
    2.69  			return temp;
    2.70  
    2.71  		case WD2797_REG_TRACK:		// Track register
    2.72 -			return ctx->track;
    2.73 +			return ctx->track_reg;
    2.74  
    2.75  		case WD2797_REG_SECTOR:		// Sector register
    2.76  			return ctx->sector;
    2.77 @@ -198,7 +203,7 @@
    2.78  				return ctx->data[ctx->data_pos++];
    2.79  			} else {
    2.80  				// command finished
    2.81 -				return 0xff;
    2.82 +				return ctx->data_reg;
    2.83  			}
    2.84  
    2.85  		default:
    2.86 @@ -215,7 +220,6 @@
    2.87  	size_t lba;
    2.88  	bool is_type1 = false;
    2.89  	int temp;
    2.90 -
    2.91  	m68k_end_timeslice();
    2.92  
    2.93  	switch (addr) {
    2.94 @@ -235,14 +239,14 @@
    2.95  				case CMD_RESTORE:
    2.96  					// Restore. Set track to 0 and throw an IRQ.
    2.97  					is_type1 = true;
    2.98 -					ctx->track = 0;
    2.99 +					ctx->track = ctx->track_reg = 0;
   2.100  					break;
   2.101  
   2.102  				case CMD_SEEK:
   2.103  					// Seek. Seek to the track specced in the Data Register.
   2.104  					is_type1 = true;
   2.105  					if (ctx->data_reg < ctx->geom_tracks) {
   2.106 -						ctx->track = ctx->data_reg;
   2.107 +						ctx->track = ctx->track_reg = ctx->data_reg;
   2.108  					} else {
   2.109  						// Seek error. :(
   2.110  						ctx->status = 0x10;
   2.111 @@ -256,26 +260,17 @@
   2.112  
   2.113  				case CMD_STEPIN:
   2.114  				case CMD_STEPOUT:
   2.115 -					// TODO! deal with trk0!
   2.116 -					// Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
   2.117 -					if (cmd == CMD_STEPIN) {
   2.118 -						ctx->last_step_dir = 1;
   2.119 -					} else {
   2.120 -						ctx->last_step_dir = -1;
   2.121 -					}
   2.122 -					is_type1 = true;
   2.123 -					break;
   2.124 -
   2.125  				case CMD_STEP_TU:
   2.126  				case CMD_STEPIN_TU:
   2.127  				case CMD_STEPOUT_TU:
   2.128  					// if this is a Step In or Step Out cmd, set the step-direction
   2.129 -					if (cmd == CMD_STEPIN_TU) {
   2.130 +					if ((cmd & ~0x10) == CMD_STEPIN) {
   2.131  						ctx->last_step_dir = 1;
   2.132 -					} else if (cmd == CMD_STEPOUT_TU) {
   2.133 +					} else if ((cmd & ~0x10) == CMD_STEPOUT) {
   2.134  						ctx->last_step_dir = -1;
   2.135  					}
   2.136  
   2.137 +
   2.138  					// Seek one step in the last direction used.
   2.139  					ctx->track += ctx->last_step_dir;
   2.140  					if (ctx->track < 0) ctx->track = 0;
   2.141 @@ -284,6 +279,10 @@
   2.142  						ctx->status = 0x10;
   2.143  						ctx->track = ctx->geom_tracks - 1;
   2.144  					}
   2.145 +					if (cmd & 0x10){
   2.146 +						ctx->track_reg = ctx->track;
   2.147 +					}
   2.148 +
   2.149  					is_type1 = true;
   2.150  					break;
   2.151  
   2.152 @@ -329,8 +328,7 @@
   2.153  			}
   2.154  
   2.155  			// If this is a Write command, check write protect status too
   2.156 -			// TODO!
   2.157 -			if (false) {
   2.158 +			if (!ctx->writeable) {
   2.159  				// Write protected disc...
   2.160  				if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) {
   2.161  					// Set Write Protect bit and bail.
   2.162 @@ -388,9 +386,9 @@
   2.163  								ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
   2.164  						// CHS parameters exceed limits
   2.165  						ctx->status = 0x10;		// Record Not Found
   2.166 -						break;
   2.167  						// Set IRQ
   2.168  						ctx->irq = true;
   2.169 +						break;
   2.170  					}
   2.171  
   2.172  					// reset data pointers
   2.173 @@ -430,12 +428,14 @@
   2.174  				case CMD_READ_TRACK:
   2.175  					// Read Track
   2.176  					// TODO! implement this
   2.177 -					ctx->head = (val & 0x02) ? 1 : 0;
   2.178 -					ctx->status = 0;
   2.179 +					// ctx->head = (val & 0x02) ? 1 : 0;
   2.180 +					// ctx->status = 0;
   2.181  					// B6, B5, B4, B3 = 0
   2.182  					// B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
   2.183  					// B1 = DRQ. Data request.
   2.184 -					ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   2.185 +					// ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   2.186 +					ctx->irq = true;
   2.187 +					ctx->status = 0x10;
   2.188  					break;
   2.189  
   2.190  				case CMD_WRITE_SECTOR:
   2.191 @@ -444,12 +444,21 @@
   2.192  
   2.193  					ctx->head = (val & 0x02) ? 1 : 0;
   2.194  					// reset data pointers
   2.195 -					ctx->data_pos = ctx->data_len = 0;
   2.196 +					ctx->data_pos = 0;
   2.197  
   2.198 -					// TODO: set "write pending" flag, and write LBA, and go from there.
   2.199 +					// Calculate number of sectors to write to disc
   2.200 +					if (cmd == CMD_WRITE_SECTOR_MULTI)
   2.201 +						/*XXX: is this the correct value?*/
   2.202 +						temp = ctx->geom_spt;
   2.203 +					else
   2.204 +						temp = 1;
   2.205 +					ctx->data_len = temp * ctx->geom_secsz;
   2.206 +
   2.207 +					lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector)) - 1;
   2.208 +					ctx->write_pos = lba * ctx->geom_secsz;
   2.209  
   2.210  					ctx->status = 0;
   2.211 -					// B6 = Write Protect. FIXME -- emulate this!
   2.212 +					// B6 = Write Protect. This would have been set earlier.
   2.213  					// B5 = 0
   2.214  					// B4 = Record Not Found. We're not going to see this... FIXME-not emulated
   2.215  					// B3 = CRC Error. Not possible.
   2.216 @@ -465,24 +474,35 @@
   2.217  					// B6 = Write Protect. FIXME -- emulate this!
   2.218  					// B5, B4, B3 = 0
   2.219  					// B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
   2.220 +					ctx->data_pos = 0;
   2.221 +					ctx->data_len = 7170;
   2.222  					// B1 = DRQ. Data request.
   2.223  					ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
   2.224 +					ctx->formatting = true;
   2.225  					break;
   2.226  
   2.227  				case CMD_FORCE_INTERRUPT:
   2.228  					// Force Interrupt...
   2.229  					// Terminates current operation and sends an interrupt
   2.230  					// TODO!
   2.231 -					ctx->status = 0;
   2.232 +					ctx->status = 0x20;
   2.233 +					if (!ctx->writeable){
   2.234 +						ctx->status |= 0x40;
   2.235 +					}
   2.236 +					if (ctx->track == 0){
   2.237 +						ctx->status = 0x04;
   2.238 +					}
   2.239  					ctx->data_pos = ctx->data_len = 0;
   2.240 -					// Set IRQ
   2.241 -					ctx->irq = true;
   2.242 +					if (cmd & 8){
   2.243 +						// Set IRQ
   2.244 +						ctx->irq = true;
   2.245 +					}
   2.246  					break;
   2.247  			}
   2.248  			break;
   2.249  
   2.250  		case WD2797_REG_TRACK:		// Track register
   2.251 -			ctx->track = val;
   2.252 +			ctx->track = ctx->track_reg = val;
   2.253  			break;
   2.254  
   2.255  		case WD2797_REG_SECTOR:		// Sector register
   2.256 @@ -492,20 +512,35 @@
   2.257  		case WD2797_REG_DATA:		// Data register
   2.258  			// Save the value written into the data register
   2.259  			ctx->data_reg = val;
   2.260 -
   2.261  			// If we're processing a write command, and there's space in the
   2.262  			// buffer, allow the write.
   2.263 -			if (ctx->data_pos < ctx->data_len) {
   2.264 -				// set IRQ if this is the last data byte
   2.265 -				if (ctx->data_pos == (ctx->data_len-1)) {
   2.266 -					// Set IRQ
   2.267 +			if (ctx->data_pos < ctx->data_len && (ctx->write_pos >= 0 || ctx->formatting)) {
   2.268 +				if (!ctx->formatting) ctx->data[ctx->data_pos] = val;
   2.269 +				// store data byte and increment pointer
   2.270 +				ctx->data_pos++;
   2.271 +
   2.272 +				// set IRQ and write data if this is the last data byte
   2.273 +				if (ctx->data_pos == ctx->data_len) {
   2.274 +					if (!ctx->formatting){
   2.275 +						fseek(ctx->disc_image, ctx->write_pos, SEEK_SET);
   2.276 +						fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image);
   2.277 +						fflush(ctx->disc_image);
   2.278 +					}
   2.279 +					// Set IRQ and reset write pointer
   2.280  					ctx->irq = true;
   2.281 +					ctx->write_pos = -1;
   2.282 +					ctx->formatting = false;
   2.283  				}
   2.284  
   2.285 -				// store data byte and increment pointer
   2.286 -				ctx->data[ctx->data_pos++] = val;
   2.287  			}
   2.288  			break;
   2.289  	}
   2.290  }
   2.291  
   2.292 +void wd2797_dma_miss(WD2797_CTX *ctx)
   2.293 +{
   2.294 +	ctx->data_pos = ctx->data_len;
   2.295 +	ctx->write_pos = 0;
   2.296 +	ctx->status = 4; /* lost data */
   2.297 +	ctx->irq = true;
   2.298 +}
     3.1 --- a/src/wd279x.h	Thu Dec 08 23:44:19 2011 +0000
     3.2 +++ b/src/wd279x.h	Sat Nov 17 19:13:08 2012 +0000
     3.3 @@ -25,6 +25,8 @@
     3.4  typedef struct {
     3.5  	// Current track, head and sector
     3.6  	int						track, head, sector;
     3.7 +	// Track and sector registers
     3.8 +	int						track_reg, sector_reg;
     3.9  	// Geometry of current disc
    3.10  	int						geom_secsz, geom_spt, geom_heads, geom_tracks;
    3.11  	// IRQ status
    3.12 @@ -42,6 +44,12 @@
    3.13  	size_t					data_pos, data_len;
    3.14  	// Current disc image file
    3.15  	FILE					*disc_image;
    3.16 +	// Write protect flag
    3.17 +	int						writeable;
    3.18 +	// LBA at which to start writing
    3.19 +	int						write_pos;
    3.20 +	// True if a format command is in progress
    3.21 +	int						formatting;
    3.22  } WD2797_CTX;
    3.23  
    3.24  /**
    3.25 @@ -88,7 +96,7 @@
    3.26   * @param	heads	Number of heads (1 or 2).
    3.27   * @return	Error code; WD279X_E_OK if everything worked OK.
    3.28   */
    3.29 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads);
    3.30 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable);
    3.31  
    3.32  /**
    3.33   * @brief	Deassign the current image file.
    3.34 @@ -111,5 +119,5 @@
    3.35   */
    3.36  void wd2797_write_reg(WD2797_CTX *ctx, uint8_t addr, uint8_t val);
    3.37  
    3.38 -
    3.39 +void wd2797_dma_miss(WD2797_CTX *ctx);
    3.40  #endif