Add support for MSR2, partial reads from GENSTAT

Sat, 17 Nov 2012 22:26:53 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sat, 17 Nov 2012 22:26:53 +0000
changeset 116
21521e62007f
parent 115
da3d10af0711
child 117
73caf968b67b

Add support for MSR2, partial reads from GENSTAT

* GENSTAT is sometimes read in 8bit mode. Handle this properly.

* Add support for the MSR2 register (additional HDD head select bit only at
the moment)

src/memory.c file | annotate | diff | revisions
src/wd2010.c file | annotate | diff | revisions
src/wd2010.h file | annotate | diff | revisions
     1.1 --- a/src/memory.c	Sat Nov 17 22:15:23 2012 +0000
     1.2 +++ b/src/memory.c	Sat Nov 17 22:26:53 2012 +0000
     1.3 @@ -472,7 +472,9 @@
     1.4  						handled = true;
     1.5  						break;
     1.6  					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
     1.7 -						/*TODO: implement P5.1 second hard drive select*/
     1.8 +						// MCR2 - UNIX PC Rev. P5.1 HDD head select b3 and potential HDD#2 select
     1.9 +						wd2010_write_reg(&state.hdc_ctx, UNIXPC_REG_MCR2, data);
    1.10 +						handled = true;
    1.11  						break;
    1.12  					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
    1.13  						break;
    1.14 @@ -546,8 +548,14 @@
    1.15  		// I/O register space, zone A
    1.16  		switch (address & 0x0F0000) {
    1.17  			case 0x010000:				// General Status Register
    1.18 -				ENFORCE_SIZE_R(bits, address, 16, "GENSTAT");
    1.19 -				return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
    1.20 +				/* ENFORCE_SIZE_R(bits, address, 16, "GENSTAT"); */
    1.21 +				if (bits == 32) {
    1.22 +					return ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
    1.23 +				} else if (bits == 16) {
    1.24 +					return (uint16_t)state.genstat;
    1.25 +				} else {
    1.26 +					return (uint8_t)(state.genstat & 0xff);
    1.27 +				}
    1.28  				break;
    1.29  			case 0x030000:				// Bus Status Register 0
    1.30  				ENFORCE_SIZE_R(bits, address, 16, "BSR0");
     2.1 --- a/src/wd2010.c	Sat Nov 17 22:15:23 2012 +0000
     2.2 +++ b/src/wd2010.c	Sat Nov 17 22:26:53 2012 +0000
     2.3 @@ -102,6 +102,8 @@
     2.4  	ctx->cylinder_low_reg = 0;
     2.5  	ctx->cylinder_high_reg = 0;
     2.6  	ctx->sdh = 0;
     2.7 +	ctx->mcr2_hdsel3 = 0;
     2.8 +	ctx->mcr2_ddrive1 = 0;
     2.9  }
    2.10  
    2.11  void wd2010_done(WD2010_CTX *ctx)
    2.12 @@ -260,6 +262,17 @@
    2.13  
    2.14  	/*cpu_log_enabled = 1;*/
    2.15  
    2.16 +	if (addr == UNIXPC_REG_MCR2) {
    2.17 +		// The UNIX PC has an "MCR2" register with the following format:
    2.18 +		//   [ 7..2 ][1][0]
    2.19 +		//   Bits 7..2: Not used
    2.20 +		//   Bit 1:     DDRIVE1 (hard disk drive 1 select - not used?)
    2.21 +		//   Bit 0:     HDSEL3  (head-select bit 3)
    2.22 +		ctx->mcr2_hdsel3 = ((val & 1) == 1);
    2.23 +		ctx->mcr2_ddrive1 = ((val & 2) == 2);
    2.24 +		return;
    2.25 +	}
    2.26 +
    2.27  	switch (addr & 0x07) {
    2.28  		case WD2010_REG_WRITE_PRECOMP_CYLINDER:
    2.29  			break;
    2.30 @@ -313,7 +326,8 @@
    2.31  						ctx->irq = true;
    2.32  						break;
    2.33  					}
    2.34 -					ctx->head = ctx->sdh & 0x07;
    2.35 +					// The SDH register provides 3 head select bits; the 4th comes from MCR2.
    2.36 +					ctx->head = (ctx->sdh & 0x07) + (ctx->mcr2_hdsel3 ? 8 : 0);
    2.37  					ctx->sector = ctx->sector_number;
    2.38  
    2.39  					ctx->formatting = cmd == CMD_WRITE_FORMAT;
     3.1 --- a/src/wd2010.h	Sat Nov 17 22:15:23 2012 +0000
     3.2 +++ b/src/wd2010.h	Sat Nov 17 22:26:53 2012 +0000
     3.3 @@ -8,16 +8,16 @@
     3.4  
     3.5  /// WD2010 registers
     3.6  typedef enum {
     3.7 -	WD2010_REG_ERROR                   = 1, ///< Error register
     3.8 -	WD2010_REG_WRITE_PRECOMP_CYLINDER  = 1, ///< Write precompensation cylinder
     3.9 -                                             ///< register
    3.10 -	WD2010_REG_SECTOR_COUNT            = 2, ///< Sector count register
    3.11 -	WD2010_REG_SECTOR_NUMBER           = 3, ///< Sector number register
    3.12 -	WD2010_REG_CYLINDER_LOW            = 4, ///< Low byte of cylinder
    3.13 -	WD2010_REG_CYLINDER_HIGH           = 5, ///< High byte of cylinder
    3.14 -	WD2010_REG_SDH                     = 6, ///< Sector size, drive, and head
    3.15 -	WD2010_REG_STATUS                   = 7, ///< Status register
    3.16 -	WD2010_REG_COMMAND                  = 7, ///< Command register
    3.17 +	WD2010_REG_ERROR					= 1, ///< Error register
    3.18 +	WD2010_REG_WRITE_PRECOMP_CYLINDER	= 1, ///< Write precompensation cylinder register
    3.19 +	WD2010_REG_SECTOR_COUNT				= 2, ///< Sector count register
    3.20 +	WD2010_REG_SECTOR_NUMBER			= 3, ///< Sector number register
    3.21 +	WD2010_REG_CYLINDER_LOW				= 4, ///< Low byte of cylinder
    3.22 +	WD2010_REG_CYLINDER_HIGH			= 5, ///< High byte of cylinder
    3.23 +	WD2010_REG_SDH						= 6, ///< Sector size, drive, and head
    3.24 +	WD2010_REG_STATUS					= 7, ///< Status register
    3.25 +	WD2010_REG_COMMAND					= 7, ///< Command register
    3.26 +	UNIXPC_REG_MCR2						= 255	///< UNIX-PC MCR2 register (special!)
    3.27  } WD2010_REG;
    3.28  
    3.29  /// WD2010 emulator error codes
    3.30 @@ -42,6 +42,8 @@
    3.31  	uint8_t					cylinder_high_reg, cylinder_low_reg;
    3.32  	// SDH register (sets sector size, drive number, and head number)
    3.33  	uint8_t					sdh;
    3.34 +	// MCR2 register (LSB is HDSEL3 - head select bit 3)
    3.35 +	bool					mcr2_hdsel3, mcr2_ddrive1;
    3.36  	// Sector number and count registers
    3.37  	int						sector_number, sector_count;
    3.38  	// Last command has the multiple sector flag set?