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