Implement memory mapping and access checking

Thu, 02 Dec 2010 17:01:34 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 02 Dec 2010 17:01:34 +0000
changeset 32
a44afcf2354c
parent 31
4fea89e86c5e
child 33
ae97a3146978

Implement memory mapping and access checking

src/main.c file | annotate | diff | revisions
src/state.h file | annotate | diff | revisions
     1.1 diff -r 4fea89e86c5e -r a44afcf2354c src/main.c
     1.2 --- a/src/main.c	Thu Dec 02 16:37:55 2010 +0000
     1.3 +++ b/src/main.c	Thu Dec 02 17:01:34 2010 +0000
     1.4 @@ -77,9 +77,9 @@
     1.5  		uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
     1.6  		if (pagebits != 0) {
     1.7  			if (writing)
     1.8 -				state.map[addr*2] |= 0x60;		// Page written to (dirty)
     1.9 +				state.map[page*2] |= 0x60;		// Page written to (dirty)
    1.10  			else
    1.11 -				state.map[addr*2] |= 0x40;		// Page accessed but not written
    1.12 +				state.map[page*2] |= 0x40;		// Page accessed but not written
    1.13  		}
    1.14  
    1.15  		// Return the address with the new physical page spliced in
    1.16 @@ -139,7 +139,77 @@
    1.17   * m68k memory read/write support functions for Musashi
    1.18   ********************************************************/
    1.19  
    1.20 -// read m68k memory
    1.21 +/**
    1.22 + * @brief	Check memory access permissions for a write operation.
    1.23 + * @note	This used to be a single macro (merged with ACCESS_CHECK_RD), but
    1.24 + * 			gcc throws warnings when you have a return-with-value in a void
    1.25 + * 			function, even if the return-with-value is completely unreachable.
    1.26 + * 			Similarly it doesn't like it if you have a return without a value
    1.27 + * 			in a non-void function, even if it's impossible to ever reach the
    1.28 + * 			return-with-no-value. UGH!
    1.29 + */
    1.30 +#define ACCESS_CHECK_WR() do {									\
    1.31 +		/* MEM_STATUS st; */									\
    1.32 +		switch (checkMemoryAccess(address, true)) {				\
    1.33 +			case MEM_ALLOWED:									\
    1.34 +				/* Access allowed */							\
    1.35 +				break;											\
    1.36 +			case MEM_PAGEFAULT:									\
    1.37 +				/* Page fault */								\
    1.38 +				state.genstat = 0x8FFF;							\
    1.39 +				m68k_pulse_bus_error();							\
    1.40 +				return;											\
    1.41 +			case MEM_UIE:										\
    1.42 +				/* User access to memory above 4MB */			\
    1.43 +				state.genstat = 0x9EFF;							\
    1.44 +				m68k_pulse_bus_error();							\
    1.45 +				return;											\
    1.46 +			case MEM_KERNEL:									\
    1.47 +			case MEM_PAGE_NO_WE:								\
    1.48 +				/* kernel access or page not write enabled */	\
    1.49 +				/* TODO: which regs need setting? */			\
    1.50 +				m68k_pulse_bus_error();							\
    1.51 +				return;											\
    1.52 +		}														\
    1.53 +	} while (false)
    1.54 +
    1.55 +/**
    1.56 + * @brief Check memory access permissions for a read operation.
    1.57 + * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
    1.58 + * 			gcc throws warnings when you have a return-with-value in a void
    1.59 + * 			function, even if the return-with-value is completely unreachable.
    1.60 + * 			Similarly it doesn't like it if you have a return without a value
    1.61 + * 			in a non-void function, even if it's impossible to ever reach the
    1.62 + * 			return-with-no-value. UGH!
    1.63 + */
    1.64 +#define ACCESS_CHECK_RD() do {									\
    1.65 +		/* MEM_STATUS st; */									\
    1.66 +		switch (checkMemoryAccess(address, false)) {			\
    1.67 +			case MEM_ALLOWED:									\
    1.68 +				/* Access allowed */							\
    1.69 +				break;											\
    1.70 +			case MEM_PAGEFAULT:									\
    1.71 +				/* Page fault */								\
    1.72 +				state.genstat = 0xCFFF;							\
    1.73 +				m68k_pulse_bus_error();							\
    1.74 +				return 0xFFFFFFFF;								\
    1.75 +			case MEM_UIE:										\
    1.76 +				/* User access to memory above 4MB */			\
    1.77 +				state.genstat = 0xDEFF;							\
    1.78 +				m68k_pulse_bus_error();							\
    1.79 +				return 0xFFFFFFFF;								\
    1.80 +			case MEM_KERNEL:									\
    1.81 +			case MEM_PAGE_NO_WE:								\
    1.82 +				/* kernel access or page not write enabled */	\
    1.83 +				/* TODO: which regs need setting? */			\
    1.84 +				m68k_pulse_bus_error();							\
    1.85 +				return 0xFFFFFFFF;								\
    1.86 +		}														\
    1.87 +	} while (false)
    1.88 +
    1.89 +/**
    1.90 + * @brief Read M68K memory, 32-bit
    1.91 + */
    1.92  uint32_t m68k_read_memory_32(uint32_t address)
    1.93  {
    1.94  	uint32_t data = 0xFFFFFFFF;
    1.95 @@ -148,12 +218,15 @@
    1.96  	if (!state.romlmap)
    1.97  		address |= 0x800000;
    1.98  
    1.99 +	// Check access permissions
   1.100 +	ACCESS_CHECK_RD();
   1.101 +
   1.102  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.103  		// ROM access
   1.104  		data = RD32(state.rom, address, ROM_SIZE - 1);
   1.105  	} else if (address <= (state.ram_size - 1)) {
   1.106 -		// RAM access -- TODO: mapping
   1.107 -		data = RD32(state.ram, address, state.ram_size - 1);
   1.108 +		// RAM access
   1.109 +		data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1);
   1.110  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.111  		// VRAM access
   1.112  		data = RD32(state.vram, address, 0x7FFF);
   1.113 @@ -167,6 +240,9 @@
   1.114  	return data;
   1.115  }
   1.116  
   1.117 +/**
   1.118 + * @brief Read M68K memory, 16-bit
   1.119 + */
   1.120  uint32_t m68k_read_memory_16(uint32_t address)
   1.121  {
   1.122  	uint16_t data = 0xFFFF;
   1.123 @@ -175,12 +251,15 @@
   1.124  	if (!state.romlmap)
   1.125  		address |= 0x800000;
   1.126  
   1.127 +	// Check access permissions
   1.128 +	ACCESS_CHECK_RD();
   1.129 +
   1.130  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.131  		// ROM access
   1.132  		data = RD16(state.rom, address, ROM_SIZE - 1);
   1.133  	} else if (address <= (state.ram_size - 1)) {
   1.134 -		// RAM access -- TODO: mapping
   1.135 -		data = RD16(state.ram, address, state.ram_size - 1);
   1.136 +		// RAM access
   1.137 +		data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1);
   1.138  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.139  		// VRAM access
   1.140  		data = RD16(state.vram, address, 0x7FFF);
   1.141 @@ -195,6 +274,9 @@
   1.142  	return data;
   1.143  }
   1.144  
   1.145 +/**
   1.146 + * @brief Read M68K memory, 8-bit
   1.147 + */
   1.148  uint32_t m68k_read_memory_8(uint32_t address)
   1.149  {
   1.150  	uint8_t data = 0xFF;
   1.151 @@ -203,12 +285,15 @@
   1.152  	if (!state.romlmap)
   1.153  		address |= 0x800000;
   1.154  
   1.155 +	// Check access permissions
   1.156 +	ACCESS_CHECK_RD();
   1.157 +
   1.158  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.159  		// ROM access
   1.160  		data = RD8(state.rom, address, ROM_SIZE - 1);
   1.161  	} else if (address <= (state.ram_size - 1)) {
   1.162 -		// RAM access -- TODO: mapping
   1.163 -		data = RD8(state.ram, address, state.ram_size - 1);
   1.164 +		// RAM access
   1.165 +		data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1);
   1.166  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.167  		// VRAM access
   1.168  		data = RD8(state.vram, address, 0x7FFF);
   1.169 @@ -223,19 +308,25 @@
   1.170  	return data;
   1.171  }
   1.172  
   1.173 -// write m68k memory
   1.174 +/**
   1.175 + * @brief Write M68K memory, 32-bit
   1.176 + */
   1.177  void m68k_write_memory_32(uint32_t address, uint32_t value)
   1.178  {
   1.179  	// If ROMLMAP is set, force system to access ROM
   1.180  	if (!state.romlmap)
   1.181  		address |= 0x800000;
   1.182  
   1.183 +	// Check access permissions
   1.184 +	ACCESS_CHECK_WR();
   1.185 +
   1.186  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.187  		// ROM access
   1.188 -		// TODO: bus error here? can't write to rom!
   1.189 +		// According to HwNote15 (John B. Milton), there is no write protection
   1.190 +		// here. You can write to ROM, but nothing happens.
   1.191  	} else if (address <= (state.ram_size - 1)) {
   1.192 -		// RAM -- TODO: mapping
   1.193 -		WR32(state.ram, address, state.ram_size - 1, value);
   1.194 +		// RAM access
   1.195 +		WR32(state.ram, mapAddr(address, true), state.ram_size - 1, value);
   1.196  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.197  		// VRAM access
   1.198  		WR32(state.vram, address, 0x7fff, value);
   1.199 @@ -250,18 +341,25 @@
   1.200  	}
   1.201  }
   1.202  
   1.203 +/**
   1.204 + * @brief Write M68K memory, 16-bit
   1.205 + */
   1.206  void m68k_write_memory_16(uint32_t address, uint32_t value)
   1.207  {
   1.208  	// If ROMLMAP is set, force system to access ROM
   1.209  	if (!state.romlmap)
   1.210  		address |= 0x800000;
   1.211  
   1.212 +	// Check access permissions
   1.213 +	ACCESS_CHECK_WR();
   1.214 +
   1.215  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.216  		// ROM access
   1.217 -		// TODO: bus error here? can't write to rom!
   1.218 +		// According to HwNote15 (John B. Milton), there is no write protection
   1.219 +		// here. You can write to ROM, but nothing happens.
   1.220  	} else if (address <= (state.ram_size - 1)) {
   1.221 -		// RAM access -- TODO: mapping
   1.222 -		WR16(state.ram, address, state.ram_size - 1, value);
   1.223 +		// RAM access
   1.224 +		WR16(state.ram, mapAddr(address, true), state.ram_size - 1, value);
   1.225  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.226  		// VRAM access
   1.227  		WR16(state.vram, address, 0x7fff, value);
   1.228 @@ -284,18 +382,25 @@
   1.229  	}
   1.230  }
   1.231  
   1.232 +/**
   1.233 + * @brief Write M68K memory, 8-bit
   1.234 + */
   1.235  void m68k_write_memory_8(uint32_t address, uint32_t value)
   1.236  {
   1.237  	// If ROMLMAP is set, force system to access ROM
   1.238  	if (!state.romlmap)
   1.239  		address |= 0x800000;
   1.240  
   1.241 +	// Check access permissions
   1.242 +	ACCESS_CHECK_WR();
   1.243 +
   1.244  	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.245  		// ROM access
   1.246 -		// TODO: bus error here? can't write to rom!
   1.247 +		// According to HwNote15 (John B. Milton), there is no write protection
   1.248 +		// here. You can write to ROM, but nothing happens.
   1.249  	} else if (address <= (state.ram_size - 1)) {
   1.250 -		// RAM access -- TODO: mapping
   1.251 -		WR8(state.ram, address, state.ram_size - 1, value);
   1.252 +		// RAM access
   1.253 +		WR8(state.ram, mapAddr(address, true), state.ram_size - 1, value);
   1.254  	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   1.255  		// VRAM access
   1.256  		WR8(state.vram, address, 0x7fff, value);
   1.257 @@ -354,7 +459,7 @@
   1.258  		printf("Could not find a suitable video mode: %s.\n", SDL_GetError());
   1.259  		exit(EXIT_FAILURE);
   1.260  	}
   1.261 -	printf("Set %dx%d at %d bits-per-pixel mode\n", screen->w, screen->h, screen->format->BitsPerPixel);
   1.262 +	printf("Set %dx%d at %d bits-per-pixel mode\n\n", screen->w, screen->h, screen->format->BitsPerPixel);
   1.263  	SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
   1.264  
   1.265  	/***
     2.1 diff -r 4fea89e86c5e -r a44afcf2354c src/state.h
     2.2 --- a/src/state.h	Thu Dec 02 16:37:55 2010 +0000
     2.3 +++ b/src/state.h	Thu Dec 02 17:01:34 2010 +0000
     2.4 @@ -27,6 +27,9 @@
     2.5  	// Map RAM
     2.6  	uint8_t		map[0x800];			///< Map RAM
     2.7  
     2.8 +	// General Status Register
     2.9 +	uint16_t	genstat;
    2.10 +
    2.11  	// GENERAL CONTROL REGISTER
    2.12  	/// GENCON.ROMLMAP -- false ORs the address with 0x800000, forcing the
    2.13  	/// 68010 to access ROM instead of RAM when booting. TRM page 2-36.