treat all DMA reads/writes as kernel mode (previously it would depend on whether the processor happens to be in user mode or kernel mode when the DMA completes, which is totally incorrect); handle 32-bit accesses that straddle page boundaries properly (all 32-bit accesses are now split into two 16-bit accesses); allow reads to the entire zero page, rather than just address 0

Fri, 18 Apr 2014 01:26:01 -0600

author
andrew@localhost
date
Fri, 18 Apr 2014 01:26:01 -0600
changeset 150
c19afa2c81db
parent 149
1124f0f5409d
child 151
b63a3999e2e7

treat all DMA reads/writes as kernel mode (previously it would depend on whether the processor happens to be in user mode or kernel mode when the DMA completes, which is totally incorrect); handle 32-bit accesses that straddle page boundaries properly (all 32-bit accesses are now split into two 16-bit accesses); allow reads to the entire zero page, rather than just address 0

src/memory.c file | annotate | diff | revisions
src/memory.h file | annotate | diff | revisions
     1.1 diff -r 1124f0f5409d -r c19afa2c81db src/memory.c
     1.2 --- a/src/memory.c	Thu Apr 17 01:58:05 2014 -0600
     1.3 +++ b/src/memory.c	Fri Apr 18 01:26:01 2014 -0600
     1.4 @@ -20,6 +20,15 @@
     1.5  
     1.6  #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
     1.7  
     1.8 +static uint32_t map_address_debug(uint32_t addr)
     1.9 +{
    1.10 +	uint16_t page = (addr >> 12) & 0x3FF;
    1.11 +
    1.12 +	// Look it up in the map RAM and get the physical page address
    1.13 +	uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
    1.14 +	return (new_page_addr << 12) + (addr & 0xFFF);
    1.15 +}
    1.16 +
    1.17  uint32_t mapAddr(uint32_t addr, bool writing)/*{{{*/
    1.18  {
    1.19  	if (addr < 0x400000) {
    1.20 @@ -70,7 +79,7 @@
    1.21  	}
    1.22  }/*}}}*/
    1.23  
    1.24 -MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)/*{{{*/
    1.25 +MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing, bool dma)/*{{{*/
    1.26  {
    1.27  	// Get the page bits for this page.
    1.28  	uint16_t page = (addr >> 12) & 0x3FF;
    1.29 @@ -83,7 +92,7 @@
    1.30  	}
    1.31  
    1.32  	// Are we in Supervisor mode?
    1.33 -	if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
    1.34 +	if (dma || (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000))
    1.35  		// Yes. We can do anything we like.
    1.36  		return MEM_ALLOWED;
    1.37  
    1.38 @@ -96,7 +105,7 @@
    1.39  
    1.40  	// User attempt to access the kernel
    1.41  	// A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
    1.42 -	if (((addr >> 19) & 0x0F) == 0) {
    1.43 +	if (((addr >> 19) & 0x0F) == 0 && !(!writing && addr <= 0x1000)) {
    1.44  		LOGS("Attempt by user code to access kernel space");
    1.45  		return MEM_KERNEL;
    1.46  	}
    1.47 @@ -107,32 +116,13 @@
    1.48  				addr, page, MAPRAM(page), state.map[page*2], state.map[(page*2)+1], pagebits);
    1.49  		return MEM_PAGE_NO_WE;
    1.50  	}
    1.51 -
    1.52  	// Page access allowed.
    1.53  	return MEM_ALLOWED;
    1.54  }/*}}}*/
    1.55  
    1.56 -
    1.57 -
    1.58 -/********************************************************
    1.59 - * m68k memory read/write support functions for Musashi
    1.60 - ********************************************************/
    1.61 -
    1.62 -/**
    1.63 - * @brief	Check memory access permissions for a write operation.
    1.64 - * @note	This used to be a single macro (merged with ACCESS_CHECK_RD), but
    1.65 - * 			gcc throws warnings when you have a return-with-value in a void
    1.66 - * 			function, even if the return-with-value is completely unreachable.
    1.67 - * 			Similarly it doesn't like it if you have a return without a value
    1.68 - * 			in a non-void function, even if it's impossible to ever reach the
    1.69 - * 			return-with-no-value. UGH!
    1.70 - */
    1.71 -/*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
    1.72 -#define ACCESS_CHECK_WR(address, bits)								\
    1.73 +#define _ACCESS_CHECK_WR_BYTE(address)								\
    1.74  	do {															\
    1.75 -		bool fault = false;											\
    1.76 -		MEM_STATUS st;												\
    1.77 -		switch (st = checkMemoryAccess(address, true)) {			\
    1.78 +		switch (st = checkMemoryAccess(address, true, false)) {			\
    1.79  			case MEM_ALLOWED:										\
    1.80  				/* Access allowed */								\
    1.81  				break;												\
    1.82 @@ -154,7 +144,33 @@
    1.83  				fault = true;										\
    1.84  				break;												\
    1.85  		}															\
    1.86 -																	\
    1.87 +	}while (0)
    1.88 +	
    1.89 +
    1.90 +
    1.91 +/********************************************************
    1.92 + * m68k memory read/write support functions for Musashi
    1.93 + ********************************************************/
    1.94 +
    1.95 +/**
    1.96 + * @brief	Check memory access permissions for a write operation.
    1.97 + * @note	This used to be a single macro (merged with ACCESS_CHECK_RD), but
    1.98 + * 			gcc throws warnings when you have a return-with-value in a void
    1.99 + * 			function, even if the return-with-value is completely unreachable.
   1.100 + * 			Similarly it doesn't like it if you have a return without a value
   1.101 + * 			in a non-void function, even if it's impossible to ever reach the
   1.102 + * 			return-with-no-value. UGH!
   1.103 + */
   1.104 +/*{{{ macro: ACCESS_CHECK_WR(address, bits)*/
   1.105 +#define ACCESS_CHECK_WR(address, bits)								\
   1.106 +	do {															\
   1.107 +		bool fault = false;											\
   1.108 +		MEM_STATUS st;												\
   1.109 +		_ACCESS_CHECK_WR_BYTE(address);								\
   1.110 +		if (!fault && bits == 32									\
   1.111 +				&& ((address + 3) & ~0xfff) != ((address & ~0xfff))){	\
   1.112 +			_ACCESS_CHECK_WR_BYTE(address + 3);						\
   1.113 +		}															\
   1.114  		if (fault) {												\
   1.115  			if (bits >= 16)											\
   1.116  				state.bsr0 = 0x7C00;								\
   1.117 @@ -169,21 +185,9 @@
   1.118  	} while (0)
   1.119  /*}}}*/
   1.120  
   1.121 -/**
   1.122 - * @brief Check memory access permissions for a read operation.
   1.123 - * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   1.124 - * 			gcc throws warnings when you have a return-with-value in a void
   1.125 - * 			function, even if the return-with-value is completely unreachable.
   1.126 - * 			Similarly it doesn't like it if you have a return without a value
   1.127 - * 			in a non-void function, even if it's impossible to ever reach the
   1.128 - * 			return-with-no-value. UGH!
   1.129 - */
   1.130 -/*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
   1.131 -#define ACCESS_CHECK_RD(address, bits)								\
   1.132 +#define _ACCESS_CHECK_RD_BYTE(address)									\
   1.133  	do {															\
   1.134 -		bool fault = false;											\
   1.135 -		MEM_STATUS st;												\
   1.136 -		switch (st = checkMemoryAccess(address, false)) {			\
   1.137 +		switch (st = checkMemoryAccess(address, false, false)) {	\
   1.138  			case MEM_ALLOWED:										\
   1.139  				/* Access allowed */								\
   1.140  				break;												\
   1.141 @@ -205,15 +209,38 @@
   1.142  				fault = true;										\
   1.143  				break;												\
   1.144  		}															\
   1.145 +	} while (0)	
   1.146 +
   1.147 +/**
   1.148 + * @brief Check memory access permissions for a read operation.
   1.149 + * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   1.150 + * 			gcc throws warnings when you have a return-with-value in a void
   1.151 + * 			function, even if the return-with-value is completely unreachable.
   1.152 + * 			Similarly it doesn't like it if you have a return without a value
   1.153 + * 			in a non-void function, even if it's impossible to ever reach the
   1.154 + * 			return-with-no-value. UGH!
   1.155 + */
   1.156 +/*{{{ macro: ACCESS_CHECK_RD(address, bits)*/
   1.157 +#define ACCESS_CHECK_RD(address, bits)								\
   1.158 +	do {															\
   1.159 +		bool fault = false;											\
   1.160 +		uint32_t faultAddr = address;								\
   1.161 +		MEM_STATUS st;												\
   1.162 +		_ACCESS_CHECK_RD_BYTE(address);								\
   1.163 +		if (!fault && bits == 32									\
   1.164 +				&& ((address + 2) & ~0xfff) != (address & ~0xfff)){	\
   1.165 +			_ACCESS_CHECK_RD_BYTE(address + 2);						\
   1.166 +			if (fault) faultAddr = address + 2;						\
   1.167 +		}															\
   1.168  																	\
   1.169  		if (fault) {												\
   1.170  			if (bits >= 16)											\
   1.171  				state.bsr0 = 0x7C00;								\
   1.172  			else													\
   1.173 -				state.bsr0 = (address & 1) ? 0x7E00 : 0x7D00;		\
   1.174 -			state.bsr0 |= (address >> 16);							\
   1.175 -			state.bsr1 = address & 0xffff;							\
   1.176 -			LOG("Bus Error while reading, addr %08X, statcode %d", address, st);		\
   1.177 +				state.bsr0 = (faultAddr & 1) ? 0x7E00 : 0x7D00;		\
   1.178 +			state.bsr0 |= (faultAddr >> 16);							\
   1.179 +			state.bsr1 = faultAddr & 0xffff;							\
   1.180 +			LOG("Bus Error while reading, addr %08X, statcode %d", faultAddr, st);		\
   1.181  			if (state.ee) m68k_pulse_bus_error();					\
   1.182  			if (bits >= 32)											\
   1.183  				return EMPTY & 0xFFFFFFFF;									\
   1.184 @@ -227,7 +254,7 @@
   1.185  {
   1.186  	// Check memory access permissions
   1.187  	bool access_ok = false;
   1.188 -	switch (checkMemoryAccess(state.dma_address, !reading)) {
   1.189 +	switch (checkMemoryAccess(state.dma_address, !reading, true)) {
   1.190  		case MEM_PAGEFAULT:
   1.191  			// Page fault
   1.192  			state.genstat = 0xABFF
   1.193 @@ -717,6 +744,20 @@
   1.194   * m68k memory read/write support functions for Musashi
   1.195   ********************************************************/
   1.196  
   1.197 +
   1.198 +static uint16_t ram_read_16(uint32_t address)
   1.199 +{
   1.200 +	if (address <= 0x1fffff) {
   1.201 +		// Base memory wraps around
   1.202 +		return RD16(state.base_ram, address, state.base_ram_size - 1);
   1.203 +	} else {
   1.204 +		if ((address <= (state.exp_ram_size + 0x200000 - 1)) && (address >= 0x200000)){
   1.205 +			return RD16(state.exp_ram, address - 0x200000, state.exp_ram_size - 1);
   1.206 +		}else
   1.207 +			return EMPTY & 0xffff;
   1.208 +	}
   1.209 +}
   1.210 +
   1.211  /**
   1.212   * @brief Read M68K memory, 32-bit
   1.213   */
   1.214 @@ -737,15 +778,11 @@
   1.215  	} else if (address <= 0x3fffff) {
   1.216  		// RAM access
   1.217  		uint32_t newAddr = mapAddr(address, false);
   1.218 -		if (newAddr <= 0x1fffff) {
   1.219 -			// Base memory wraps around
   1.220 -			return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
   1.221 -		} else {
   1.222 -			if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
   1.223 -				return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
   1.224 -			else
   1.225 -				return EMPTY & 0xffffffff;
   1.226 -		}
   1.227 +		// Base memory wraps around
   1.228 +		data = ((ram_read_16(newAddr) << 16) | 
   1.229 +			ram_read_16(mapAddr(address + 2, false)));
   1.230 +
   1.231 +		return (data);
   1.232  	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.233  		// I/O register space, zone A
   1.234  		switch (address & 0x0F0000) {
   1.235 @@ -867,6 +904,20 @@
   1.236  	return data;
   1.237  }/*}}}*/
   1.238  
   1.239 +
   1.240 +static void ram_write_16(uint32_t address, uint32_t value)/*{{{*/
   1.241 +{
   1.242 +	if (address <= 0x1fffff) {
   1.243 +		if (address < state.base_ram_size) {
   1.244 +			WR16(state.base_ram, address, state.base_ram_size - 1, value);
   1.245 +		}
   1.246 +	} else {
   1.247 +		if ((address - 0x200000) < state.exp_ram_size) {
   1.248 +			WR16(state.exp_ram, address - 0x200000, state.exp_ram_size - 1, value);
   1.249 +		}
   1.250 +	}
   1.251 +}
   1.252 +
   1.253  /**
   1.254   * @brief Write M68K memory, 32-bit
   1.255   */
   1.256 @@ -878,21 +929,13 @@
   1.257  
   1.258  	// Check access permissions
   1.259  	ACCESS_CHECK_WR(address, 32);
   1.260 -
   1.261  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.262  		// ROM access
   1.263  	} else if (address <= 0x3FFFFF) {
   1.264  		// RAM access
   1.265  		uint32_t newAddr = mapAddr(address, true);
   1.266 -		if (newAddr <= 0x1fffff) {
   1.267 -			if (newAddr < state.base_ram_size) {
   1.268 -				WR32(state.base_ram, newAddr, state.base_ram_size - 1, value);
   1.269 -			}
   1.270 -		} else {
   1.271 -			if ((newAddr - 0x200000) < state.exp_ram_size) {
   1.272 -				WR32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1, value);
   1.273 -			}
   1.274 -		}
   1.275 +		ram_write_16(newAddr, (value & 0xffff0000) >> 16);
   1.276 +		ram_write_16(mapAddr(address + 2, true), (value & 0xffff));
   1.277  	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.278  		// I/O register space, zone A
   1.279  		switch (address & 0x0F0000) {
   1.280 @@ -1008,20 +1051,12 @@
   1.281  uint32_t m68k_read_disassembler_32(uint32_t addr)
   1.282  {
   1.283  	if (addr < 0x400000) {
   1.284 -		uint16_t page = (addr >> 12) & 0x3FF;
   1.285 -		uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
   1.286 -		uint32_t newAddr = (new_page_addr << 12) + (addr & 0xFFF);
   1.287 -		if (newAddr <= 0x1fffff) {
   1.288 -			if (newAddr >= state.base_ram_size)
   1.289 -				return EMPTY;
   1.290 -			else
   1.291 -				return RD32(state.base_ram, newAddr, state.base_ram_size - 1);
   1.292 -		} else {
   1.293 -			if ((newAddr <= (state.exp_ram_size + 0x200000 - 1)) && (newAddr >= 0x200000))
   1.294 -				return RD32(state.exp_ram, newAddr - 0x200000, state.exp_ram_size - 1);
   1.295 -			else
   1.296 -				return EMPTY;
   1.297 -		}
   1.298 +		uint32_t newAddrHigh, newAddrLow;
   1.299 +		newAddrHigh = map_address_debug(addr);
   1.300 +		newAddrLow = map_address_debug(addr + 2);
   1.301 +		return ((ram_read_16(newAddrHigh) << 16) | 
   1.302 +			ram_read_16(newAddrLow));
   1.303 +
   1.304  	} else {
   1.305  		printf(">>> WARNING Disassembler RD32 out of range 0x%08X\n", addr);
   1.306  		return EMPTY;
     2.1 diff -r 1124f0f5409d -r c19afa2c81db src/memory.h
     2.2 --- a/src/memory.h	Thu Apr 17 01:58:05 2014 -0600
     2.3 +++ b/src/memory.h	Fri Apr 18 01:26:01 2014 -0600
     2.4 @@ -60,7 +60,7 @@
     2.5   * @return	One of the MEM_STATUS constants, specifying whether the access is
     2.6   * 			permitted, or what error occurred.
     2.7   */
     2.8 -MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing);
     2.9 +MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing, bool dma);
    2.10  
    2.11  /**
    2.12   * @brief	Map a CPU memory address into physical memory space.