src/main.c

Thu, 02 Dec 2010 22:27:43 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 02 Dec 2010 22:27:43 +0000
changeset 38
b948045ca964
parent 37
87662afa1d98
child 39
cab49f90c3b9
permissions
-rw-r--r--

add proper tracking of unhandled R/W operations

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <stdint.h>
     4 #include <stdbool.h>
     5 #include <malloc.h>
     6 #include <string.h>
     8 #include "SDL.h"
    10 #include "musashi/m68k.h"
    11 #include "version.h"
    12 #include "state.h"
    14 void FAIL(char *err)
    15 {
    16 	state_done();
    17 	fprintf(stderr, "ERROR: %s\nExiting...\n", err);
    18 	exit(EXIT_FAILURE);
    19 }
    21 /***********************************
    22  * Array read/write utility macros
    23  * "Don't Repeat Yourself" :)
    24  ***********************************/
    26 /// Array read, 32-bit
    27 #define RD32(array, address, andmask)							\
    28 	(((uint32_t)array[(address + 0) & (andmask)] << 24) |		\
    29 	 ((uint32_t)array[(address + 1) & (andmask)] << 16) |		\
    30 	 ((uint32_t)array[(address + 2) & (andmask)] << 8)  |		\
    31 	 ((uint32_t)array[(address + 3) & (andmask)]))
    33 /// Array read, 16-bit
    34 #define RD16(array, address, andmask)							\
    35 	(((uint32_t)array[(address + 0) & (andmask)] << 8)  |		\
    36 	 ((uint32_t)array[(address + 1) & (andmask)]))
    38 /// Array read, 8-bit
    39 #define RD8(array, address, andmask)							\
    40 	((uint32_t)array[(address + 0) & (andmask)])
    42 /// Array write, 32-bit
    43 #define WR32(array, address, andmask, value) {					\
    44 	array[(address + 0) & (andmask)] = (value >> 24) & 0xff;	\
    45 	array[(address + 1) & (andmask)] = (value >> 16) & 0xff;	\
    46 	array[(address + 2) & (andmask)] = (value >> 8)  & 0xff;	\
    47 	array[(address + 3) & (andmask)] =  value        & 0xff;	\
    48 }
    50 /// Array write, 16-bit
    51 #define WR16(array, address, andmask, value) {					\
    52 	array[(address + 0) & (andmask)] = (value >> 8)  & 0xff;	\
    53 	array[(address + 1) & (andmask)] =  value        & 0xff;	\
    54 }
    56 /// Array write, 8-bit
    57 #define WR8(array, address, andmask, value)						\
    58 	array[(address + 0) & (andmask)] =  value        & 0xff;
    60 /******************
    61  * Memory mapping
    62  ******************/
    64 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
    66 uint32_t mapAddr(uint32_t addr, bool writing)
    67 {
    68 	if (addr < 0x400000) {
    69 		// RAM access. Check against the Map RAM
    70 		// Start by getting the original page address
    71 		uint16_t page = (addr >> 12) & 0x3FF;
    73 		// Look it up in the map RAM and get the physical page address
    74 		uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
    76 		// Update the Page Status bits
    77 		uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
    78 		if (pagebits != 0) {
    79 			if (writing)
    80 				state.map[page*2] |= 0x60;		// Page written to (dirty)
    81 			else
    82 				state.map[page*2] |= 0x40;		// Page accessed but not written
    83 		}
    85 		// Return the address with the new physical page spliced in
    86 		return (new_page_addr << 12) + (addr & 0xFFF);
    87 	} else {
    88 		// I/O, VRAM or MapRAM space; no mapping is performed or required
    89 		// TODO: assert here?
    90 		return addr;
    91 	}
    92 }
    94 typedef enum {
    95 	MEM_ALLOWED = 0,
    96 	MEM_PAGEFAULT,		// Page fault -- page not present
    97 	MEM_PAGE_NO_WE,		// Page not write enabled
    98 	MEM_KERNEL,			// User attempted to access kernel memory
    99 	MEM_UIE				// User Nonmemory Location Access
   100 } MEM_STATUS;
   102 // check memory access permissions
   103 MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)
   104 {
   105 	// Are we in Supervisor mode?
   106 	if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
   107 		// Yes. We can do anything we like.
   108 		return MEM_ALLOWED;
   110 	// If we're here, then we must be in User mode.
   111 	// Check that the user didn't access memory outside of the RAM area
   112 	if (addr >= 0x400000)
   113 		return MEM_UIE;
   115 	// This leaves us with Page Fault checking. Get the page bits for this page.
   116 	uint16_t page = (addr >> 12) & 0x3FF;
   117 	uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
   119 	// Check page is present
   120 	if ((pagebits & 0x03) == 0)
   121 		return MEM_PAGEFAULT;
   123 	// User attempt to access the kernel
   124 	// A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
   125 	if (((addr >> 19) & 0x0F) == 0)
   126 		return MEM_KERNEL;
   128 	// Check page is write enabled
   129 	if ((pagebits & 0x04) == 0)
   130 		return MEM_PAGE_NO_WE;
   132 	// Page access allowed.
   133 	return MEM_ALLOWED;
   134 }
   136 #undef MAPRAM
   138 /********************************************************
   139  * m68k memory read/write support functions for Musashi
   140  ********************************************************/
   142 /**
   143  * @brief	Check memory access permissions for a write operation.
   144  * @note	This used to be a single macro (merged with ACCESS_CHECK_RD), but
   145  * 			gcc throws warnings when you have a return-with-value in a void
   146  * 			function, even if the return-with-value is completely unreachable.
   147  * 			Similarly it doesn't like it if you have a return without a value
   148  * 			in a non-void function, even if it's impossible to ever reach the
   149  * 			return-with-no-value. UGH!
   150  */
   151 #define ACCESS_CHECK_WR(address, bits) do {							\
   152 		bool fault = false;											\
   153 		/* MEM_STATUS st; */										\
   154 		switch (checkMemoryAccess(address, true)) {					\
   155 			case MEM_ALLOWED:										\
   156 				/* Access allowed */								\
   157 				break;												\
   158 			case MEM_PAGEFAULT:										\
   159 				/* Page fault */									\
   160 				state.genstat = 0x8FFF;								\
   161 				fault = true;										\
   162 				break;												\
   163 			case MEM_UIE:											\
   164 				/* User access to memory above 4MB */				\
   165 				state.genstat = 0x9EFF;								\
   166 				fault = true;										\
   167 				break;												\
   168 			case MEM_KERNEL:										\
   169 			case MEM_PAGE_NO_WE:									\
   170 				/* kernel access or page not write enabled */		\
   171 				/* TODO: which regs need setting? */				\
   172 				fault = true;										\
   173 				break;												\
   174 		}															\
   175 																	\
   176 		if (fault) {												\
   177 			if (bits >= 16)											\
   178 				state.bsr0 = 0x7F00;								\
   179 			else													\
   180 				state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00;		\
   181 			state.bsr0 |= (address >> 16);							\
   182 			state.bsr1 = address & 0xffff;							\
   183 			printf("ERR: BusError WR\n");							\
   184 			m68k_pulse_bus_error();									\
   185 			return;													\
   186 		}															\
   187 	} while (false)
   189 /**
   190  * @brief Check memory access permissions for a read operation.
   191  * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   192  * 			gcc throws warnings when you have a return-with-value in a void
   193  * 			function, even if the return-with-value is completely unreachable.
   194  * 			Similarly it doesn't like it if you have a return without a value
   195  * 			in a non-void function, even if it's impossible to ever reach the
   196  * 			return-with-no-value. UGH!
   197  */
   198 #define ACCESS_CHECK_RD(address, bits) do {							\
   199 		bool fault = false;											\
   200 		/* MEM_STATUS st; */										\
   201 		switch (checkMemoryAccess(address, false)) {				\
   202 			case MEM_ALLOWED:										\
   203 				/* Access allowed */								\
   204 				break;												\
   205 			case MEM_PAGEFAULT:										\
   206 				/* Page fault */									\
   207 				state.genstat = 0x8FFF;								\
   208 				fault = true;										\
   209 				break;												\
   210 			case MEM_UIE:											\
   211 				/* User access to memory above 4MB */				\
   212 				state.genstat = 0x9EFF;								\
   213 				fault = true;										\
   214 				break;												\
   215 			case MEM_KERNEL:										\
   216 			case MEM_PAGE_NO_WE:									\
   217 				/* kernel access or page not write enabled */		\
   218 				/* TODO: which regs need setting? */				\
   219 				fault = true;										\
   220 				break;												\
   221 		}															\
   222 																	\
   223 		if (fault) {												\
   224 			if (bits >= 16)											\
   225 				state.bsr0 = 0x7F00;								\
   226 			else													\
   227 				state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00;		\
   228 			state.bsr0 |= (address >> 16);							\
   229 			state.bsr1 = address & 0xffff;							\
   230 			printf("ERR: BusError RD\n");							\
   231 			m68k_pulse_bus_error();									\
   232 			return 0xFFFFFFFF;										\
   233 		}															\
   234 	} while (false)
   236 // Logging macros
   237 #define LOG_NOT_HANDLED_R(bits)																	\
   238 	do {																						\
   239 		if (!handled)																			\
   240 			printf("unhandled read%02d, addr=0x%08X\n", bits, address);							\
   241 	} while (0);
   243 #define LOG_NOT_HANDLED_W(bits)																	\
   244 	do {																						\
   245 		if (!handled)																			\
   246 			printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, value);	\
   247 	} while (0);
   249 /**
   250  * @brief Read M68K memory, 32-bit
   251  */
   252 uint32_t m68k_read_memory_32(uint32_t address)
   253 {
   254 	uint32_t data = 0xFFFFFFFF;
   255 	bool handled = false;
   257 	// If ROMLMAP is set, force system to access ROM
   258 	if (!state.romlmap)
   259 		address |= 0x800000;
   261 	// Check access permissions
   262 	ACCESS_CHECK_RD(address, 32);
   264 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   265 		// ROM access
   266 		data = RD32(state.rom, address, ROM_SIZE - 1);
   267 		handled = true;
   268 	} else if (address <= (state.ram_size - 1)) {
   269 		// RAM access
   270 		data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1);
   271 		handled = true;
   272 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   273 		// I/O register space, zone A
   274 //		printf("RD32 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   275 		switch (address & 0x0F0000) {
   276 			case 0x000000:				// Map RAM access
   277 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
   278 				data = RD32(state.map, address, 0x7FF);
   279 				handled = true;
   280 				break;
   281 			case 0x010000:				// General Status Register
   282 				data = ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
   283 				handled = true;
   284 				break;
   285 			case 0x020000:				// Video RAM
   286 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
   287 				data = RD32(state.vram, address, 0x7FFF);
   288 				handled = true;
   289 				break;
   290 			case 0x030000:				// Bus Status Register 0
   291 				data = ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
   292 				handled = true;
   293 				break;
   294 			case 0x040000:				// Bus Status Register 1
   295 				data = ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
   296 				handled = true;
   297 				break;
   298 			case 0x050000:				// Phone status
   299 				break;
   300 			case 0x060000:				// DMA Count
   301 				break;
   302 			case 0x070000:				// Line Printer Status Register
   303 				break;
   304 			case 0x080000:				// Real Time Clock
   305 				break;
   306 			case 0x090000:				// Phone registers
   307 				switch (address & 0x0FF000) {
   308 					case 0x090000:		// Handset relay
   309 					case 0x098000:
   310 						break;
   311 					case 0x091000:		// Line select 2
   312 					case 0x099000:
   313 						break;
   314 					case 0x092000:		// Hook relay 1
   315 					case 0x09A000:
   316 						break;
   317 					case 0x093000:		// Hook relay 2
   318 					case 0x09B000:
   319 						break;
   320 					case 0x094000:		// Line 1 hold
   321 					case 0x09C000:
   322 						break;
   323 					case 0x095000:		// Line 2 hold
   324 					case 0x09D000:
   325 						break;
   326 					case 0x096000:		// Line 1 A-lead
   327 					case 0x09E000:
   328 						break;
   329 					case 0x097000:		// Line 2 A-lead
   330 					case 0x09F000:
   331 						break;
   332 				}
   333 				break;
   334 			case 0x0A0000:				// Miscellaneous Control Register
   335 				break;
   336 			case 0x0B0000:				// TM/DIALWR
   337 				break;
   338 			case 0x0C0000:				// CSR
   339 				break;
   340 			case 0x0D0000:				// DMA Address Register
   341 				break;
   342 			case 0x0E0000:				// Disk Control Register
   343 				break;
   344 			case 0x0F0000:				// Line Printer Data Register
   345 				break;
   346 		}
   347 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   348 		// I/O register space, zone B
   349 		switch (address & 0xF00000) {
   350 			case 0xC00000:				// Expansion slots
   351 			case 0xD00000:
   352 				switch (address & 0xFC0000) {
   353 					case 0xC00000:		// Expansion slot 0
   354 					case 0xC40000:		// Expansion slot 1
   355 					case 0xC80000:		// Expansion slot 2
   356 					case 0xCC0000:		// Expansion slot 3
   357 					case 0xD00000:		// Expansion slot 4
   358 					case 0xD40000:		// Expansion slot 5
   359 					case 0xD80000:		// Expansion slot 6
   360 					case 0xDC0000:		// Expansion slot 7
   361 						fprintf(stderr, "NOTE: RD32 from expansion card space, addr=0x%08X\n", address);
   362 						break;
   363 				}
   364 				break;
   365 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   366 			case 0xF00000:
   367 				switch (address & 0x070000) {
   368 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   369 						break;
   370 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   371 						break;
   372 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   373 						break;
   374 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   375 						break;
   376 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   377 						switch (address & 0x077000) {
   378 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   379 								break;
   380 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   381 								break;
   382 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   383 								break;
   384 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   385 								break;
   386 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   387 								break;
   388 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   389 								break;
   390 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   391 								break;
   392 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   393 								break;
   394 						}
   395 						break;
   396 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   397 						break;
   398 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   399 						switch (address & 0x07F000) {
   400 							default:
   401 								break;
   402 						}
   403 						break;
   404 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   405 						break;
   406 				}
   407 		}
   408 	}
   410 	LOG_NOT_HANDLED_R(32);
   411 	return data;
   412 }
   414 /**
   415  * @brief Read M68K memory, 16-bit
   416  */
   417 uint32_t m68k_read_memory_16(uint32_t address)
   418 {
   419 	uint16_t data = 0xFFFF;
   420 	bool handled = false;
   422 	// If ROMLMAP is set, force system to access ROM
   423 	if (!state.romlmap)
   424 		address |= 0x800000;
   426 	// Check access permissions
   427 	ACCESS_CHECK_RD(address, 16);
   429 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   430 		// ROM access
   431 		data = RD16(state.rom, address, ROM_SIZE - 1);
   432 		handled = true;
   433 	} else if (address <= (state.ram_size - 1)) {
   434 		// RAM access
   435 		data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1);
   436 		handled = true;
   437 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   438 		// I/O register space, zone A
   439 		switch (address & 0x0F0000) {
   440 			case 0x000000:				// Map RAM access
   441 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
   442 				data = RD16(state.map, address, 0x7FF);
   443 				handled = true;
   444 				break;
   445 			case 0x010000:				// General Status Register
   446 				data = state.genstat;
   447 				handled = true;
   448 				break;
   449 			case 0x020000:				// Video RAM
   450 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
   451 				data = RD16(state.vram, address, 0x7FFF);
   452 				handled = true;
   453 				break;
   454 			case 0x030000:				// Bus Status Register 0
   455 				data = state.bsr0;
   456 				handled = true;
   457 				break;
   458 			case 0x040000:				// Bus Status Register 1
   459 				data = state.bsr1;
   460 				handled = true;
   461 				break;
   462 			case 0x050000:				// Phone status
   463 				break;
   464 			case 0x060000:				// DMA Count
   465 				break;
   466 			case 0x070000:				// Line Printer Status Register
   467 				break;
   468 			case 0x080000:				// Real Time Clock
   469 				break;
   470 			case 0x090000:				// Phone registers
   471 				switch (address & 0x0FF000) {
   472 					case 0x090000:		// Handset relay
   473 					case 0x098000:
   474 						break;
   475 					case 0x091000:		// Line select 2
   476 					case 0x099000:
   477 						break;
   478 					case 0x092000:		// Hook relay 1
   479 					case 0x09A000:
   480 						break;
   481 					case 0x093000:		// Hook relay 2
   482 					case 0x09B000:
   483 						break;
   484 					case 0x094000:		// Line 1 hold
   485 					case 0x09C000:
   486 						break;
   487 					case 0x095000:		// Line 2 hold
   488 					case 0x09D000:
   489 						break;
   490 					case 0x096000:		// Line 1 A-lead
   491 					case 0x09E000:
   492 						break;
   493 					case 0x097000:		// Line 2 A-lead
   494 					case 0x09F000:
   495 						break;
   496 				}
   497 				break;
   498 			case 0x0A0000:				// Miscellaneous Control Register
   499 				break;
   500 			case 0x0B0000:				// TM/DIALWR
   501 				break;
   502 			case 0x0C0000:				// CSR
   503 				break;
   504 			case 0x0D0000:				// DMA Address Register
   505 				break;
   506 			case 0x0E0000:				// Disk Control Register
   507 				break;
   508 			case 0x0F0000:				// Line Printer Data Register
   509 				break;
   510 		}
   511 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   512 		// I/O register space, zone B
   513 		switch (address & 0xF00000) {
   514 			case 0xC00000:				// Expansion slots
   515 			case 0xD00000:
   516 				switch (address & 0xFC0000) {
   517 					case 0xC00000:		// Expansion slot 0
   518 					case 0xC40000:		// Expansion slot 1
   519 					case 0xC80000:		// Expansion slot 2
   520 					case 0xCC0000:		// Expansion slot 3
   521 					case 0xD00000:		// Expansion slot 4
   522 					case 0xD40000:		// Expansion slot 5
   523 					case 0xD80000:		// Expansion slot 6
   524 					case 0xDC0000:		// Expansion slot 7
   525 						fprintf(stderr, "NOTE: RD16 from expansion card space, addr=0x%08X\n", address);
   526 						break;
   527 				}
   528 				break;
   529 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   530 			case 0xF00000:
   531 				switch (address & 0x070000) {
   532 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   533 						break;
   534 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   535 						break;
   536 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   537 						break;
   538 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   539 						break;
   540 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   541 						switch (address & 0x077000) {
   542 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   543 								break;
   544 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   545 								break;
   546 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   547 								break;
   548 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   549 								break;
   550 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   551 								break;
   552 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   553 								break;
   554 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   555 								break;
   556 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   557 								break;
   558 						}
   559 						break;
   560 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   561 						break;
   562 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   563 						switch (address & 0x07F000) {
   564 							default:
   565 								break;
   566 						}
   567 						break;
   568 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   569 						break;
   570 				}
   571 		}
   572 	}
   574 	LOG_NOT_HANDLED_R(32);
   575 	return data;
   576 }
   578 /**
   579  * @brief Read M68K memory, 8-bit
   580  */
   581 uint32_t m68k_read_memory_8(uint32_t address)
   582 {
   583 	uint8_t data = 0xFF;
   584 	bool handled = false;
   586 	// If ROMLMAP is set, force system to access ROM
   587 	if (!state.romlmap)
   588 		address |= 0x800000;
   590 	// Check access permissions
   591 	ACCESS_CHECK_RD(address, 8);
   593 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   594 		// ROM access
   595 		data = RD8(state.rom, address, ROM_SIZE - 1);
   596 		handled = true;
   597 	} else if (address <= (state.ram_size - 1)) {
   598 		// RAM access
   599 		data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1);
   600 		handled = true;
   601 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   602 		// I/O register space, zone A
   603 		switch (address & 0x0F0000) {
   604 			case 0x000000:				// Map RAM access
   605 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
   606 				data = RD8(state.map, address, 0x7FF);
   607 				handled = true;
   608 				break;
   609 			case 0x010000:				// General Status Register
   610 				if ((address & 1) == 0)
   611 					data = (state.genstat >> 8) & 0xff;
   612 				else
   613 					data = (state.genstat)      & 0xff;
   614 				handled = true;
   615 				break;
   616 			case 0x020000:				// Video RAM
   617 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
   618 				data = RD8(state.vram, address, 0x7FFF);
   619 				handled = true;
   620 				break;
   621 			case 0x030000:				// Bus Status Register 0
   622 				if ((address & 1) == 0)
   623 					data = (state.bsr0 >> 8) & 0xff;
   624 				else
   625 					data = (state.bsr0)      & 0xff;
   626 				handled = true;
   627 				break;
   628 			case 0x040000:				// Bus Status Register 1
   629 				if ((address & 1) == 0)
   630 					data = (state.bsr1 >> 8) & 0xff;
   631 				else
   632 					data = (state.bsr1)      & 0xff;
   633 				handled = true;
   634 				break;
   635 			case 0x050000:				// Phone status
   636 				break;
   637 			case 0x060000:				// DMA Count
   638 				break;
   639 			case 0x070000:				// Line Printer Status Register
   640 				break;
   641 			case 0x080000:				// Real Time Clock
   642 				break;
   643 			case 0x090000:				// Phone registers
   644 				switch (address & 0x0FF000) {
   645 					case 0x090000:		// Handset relay
   646 					case 0x098000:
   647 						break;
   648 					case 0x091000:		// Line select 2
   649 					case 0x099000:
   650 						break;
   651 					case 0x092000:		// Hook relay 1
   652 					case 0x09A000:
   653 						break;
   654 					case 0x093000:		// Hook relay 2
   655 					case 0x09B000:
   656 						break;
   657 					case 0x094000:		// Line 1 hold
   658 					case 0x09C000:
   659 						break;
   660 					case 0x095000:		// Line 2 hold
   661 					case 0x09D000:
   662 						break;
   663 					case 0x096000:		// Line 1 A-lead
   664 					case 0x09E000:
   665 						break;
   666 					case 0x097000:		// Line 2 A-lead
   667 					case 0x09F000:
   668 						break;
   669 				}
   670 				break;
   671 			case 0x0A0000:				// Miscellaneous Control Register
   672 				break;
   673 			case 0x0B0000:				// TM/DIALWR
   674 				break;
   675 			case 0x0C0000:				// CSR
   676 				break;
   677 			case 0x0D0000:				// DMA Address Register
   678 				break;
   679 			case 0x0E0000:				// Disk Control Register
   680 				break;
   681 			case 0x0F0000:				// Line Printer Data Register
   682 				break;
   683 		}
   684 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   685 		// I/O register space, zone B
   686 		switch (address & 0xF00000) {
   687 			case 0xC00000:				// Expansion slots
   688 			case 0xD00000:
   689 				switch (address & 0xFC0000) {
   690 					case 0xC00000:		// Expansion slot 0
   691 					case 0xC40000:		// Expansion slot 1
   692 					case 0xC80000:		// Expansion slot 2
   693 					case 0xCC0000:		// Expansion slot 3
   694 					case 0xD00000:		// Expansion slot 4
   695 					case 0xD40000:		// Expansion slot 5
   696 					case 0xD80000:		// Expansion slot 6
   697 					case 0xDC0000:		// Expansion slot 7
   698 						fprintf(stderr, "NOTE: RD8 from expansion card space, addr=0x%08X\n", address);
   699 						break;
   700 				}
   701 				break;
   702 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   703 			case 0xF00000:
   704 				switch (address & 0x070000) {
   705 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   706 						break;
   707 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   708 						break;
   709 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   710 						break;
   711 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   712 						break;
   713 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   714 						switch (address & 0x077000) {
   715 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   716 								break;
   717 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   718 								break;
   719 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   720 								break;
   721 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   722 								break;
   723 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   724 								break;
   725 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   726 								break;
   727 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   728 								break;
   729 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   730 								break;
   731 						}
   732 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   733 						break;
   734 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   735 						switch (address & 0x07F000) {
   736 							default:
   737 								break;
   738 						}
   739 						break;
   740 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   741 						break;
   742 				}
   743 		}
   744 	}
   746 	LOG_NOT_HANDLED_R(8);
   748 	return data;
   749 }
   751 /**
   752  * @brief Write M68K memory, 32-bit
   753  */
   754 void m68k_write_memory_32(uint32_t address, uint32_t value)
   755 {
   756 	bool handled = false;
   758 	// If ROMLMAP is set, force system to access ROM
   759 	if (!state.romlmap)
   760 		address |= 0x800000;
   762 	// Check access permissions
   763 	ACCESS_CHECK_WR(address, 32);
   765 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   766 		// ROM access
   767 		handled = true;
   768 	} else if (address <= (state.ram_size - 1)) {
   769 		// RAM access
   770 		WR32(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   771 		handled = true;
   772 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   773 		// I/O register space, zone A
   774 		switch (address & 0x0F0000) {
   775 			case 0x000000:				// Map RAM access
   776 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   777 				WR32(state.map, address, 0x7FF, value);
   778 				handled = true;
   779 				break;
   780 			case 0x010000:				// General Status Register
   781 				state.genstat = (value & 0xffff);
   782 				handled = true;
   783 				break;
   784 			case 0x020000:				// Video RAM
   785 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   786 				WR32(state.vram, address, 0x7FFF, value);
   787 				handled = true;
   788 				break;
   789 			case 0x030000:				// Bus Status Register 0
   790 				break;
   791 			case 0x040000:				// Bus Status Register 1
   792 				break;
   793 			case 0x050000:				// Phone status
   794 				break;
   795 			case 0x060000:				// DMA Count
   796 				break;
   797 			case 0x070000:				// Line Printer Status Register
   798 				break;
   799 			case 0x080000:				// Real Time Clock
   800 				break;
   801 			case 0x090000:				// Phone registers
   802 				switch (address & 0x0FF000) {
   803 					case 0x090000:		// Handset relay
   804 					case 0x098000:
   805 						break;
   806 					case 0x091000:		// Line select 2
   807 					case 0x099000:
   808 						break;
   809 					case 0x092000:		// Hook relay 1
   810 					case 0x09A000:
   811 						break;
   812 					case 0x093000:		// Hook relay 2
   813 					case 0x09B000:
   814 						break;
   815 					case 0x094000:		// Line 1 hold
   816 					case 0x09C000:
   817 						break;
   818 					case 0x095000:		// Line 2 hold
   819 					case 0x09D000:
   820 						break;
   821 					case 0x096000:		// Line 1 A-lead
   822 					case 0x09E000:
   823 						break;
   824 					case 0x097000:		// Line 2 A-lead
   825 					case 0x09F000:
   826 						break;
   827 				}
   828 				break;
   829 			case 0x0A0000:				// Miscellaneous Control Register
   830 				break;
   831 			case 0x0B0000:				// TM/DIALWR
   832 				break;
   833 			case 0x0C0000:				// CSR
   834 				break;
   835 			case 0x0D0000:				// DMA Address Register
   836 				break;
   837 			case 0x0E0000:				// Disk Control Register
   838 				break;
   839 			case 0x0F0000:				// Line Printer Data Register
   840 				break;
   841 		}
   842 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   843 		// I/O register space, zone B
   844 		switch (address & 0xF00000) {
   845 			case 0xC00000:				// Expansion slots
   846 			case 0xD00000:
   847 				switch (address & 0xFC0000) {
   848 					case 0xC00000:		// Expansion slot 0
   849 					case 0xC40000:		// Expansion slot 1
   850 					case 0xC80000:		// Expansion slot 2
   851 					case 0xCC0000:		// Expansion slot 3
   852 					case 0xD00000:		// Expansion slot 4
   853 					case 0xD40000:		// Expansion slot 5
   854 					case 0xD80000:		// Expansion slot 6
   855 					case 0xDC0000:		// Expansion slot 7
   856 						fprintf(stderr, "NOTE: WR32 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
   857 						handled = true;
   858 						break;
   859 				}
   860 				break;
   861 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   862 			case 0xF00000:
   863 				switch (address & 0x070000) {
   864 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   865 						break;
   866 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   867 						break;
   868 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   869 						break;
   870 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   871 						break;
   872 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   873 						switch (address & 0x077000) {
   874 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   875 								break;
   876 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   877 								break;
   878 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   879 								break;
   880 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   881 								state.romlmap = ((value & 0x8000) == 0x8000);
   882 								break;
   883 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   884 								break;
   885 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   886 								break;
   887 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   888 								break;
   889 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   890 								break;
   891 						}
   892 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   893 						break;
   894 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   895 						switch (address & 0x07F000) {
   896 							default:
   897 								break;
   898 						}
   899 						break;
   900 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   901 						break;
   902 				}
   903 		}
   904 	}
   906 	LOG_NOT_HANDLED_W(32);
   907 }
   909 /**
   910  * @brief Write M68K memory, 16-bit
   911  */
   912 void m68k_write_memory_16(uint32_t address, uint32_t value)
   913 {
   914 	bool handled = false;
   916 	// If ROMLMAP is set, force system to access ROM
   917 	if (!state.romlmap)
   918 		address |= 0x800000;
   920 	// Check access permissions
   921 	ACCESS_CHECK_WR(address, 16);
   923 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   924 		// ROM access
   925 		handled = true;
   926 	} else if (address <= (state.ram_size - 1)) {
   927 		// RAM access
   928 		WR16(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   929 		handled = true;
   930 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   931 		// I/O register space, zone A
   932 		switch (address & 0x0F0000) {
   933 			case 0x000000:				// Map RAM access
   934 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   935 				WR16(state.map, address, 0x7FF, value);
   936 				handled = true;
   937 				break;
   938 			case 0x010000:				// General Status Register (read only)
   939 				handled = true;
   940 				break;
   941 			case 0x020000:				// Video RAM
   942 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   943 				WR16(state.vram, address, 0x7FFF, value);
   944 				handled = true;
   945 				break;
   946 			case 0x030000:				// Bus Status Register 0 (read only)
   947 				handled = true;
   948 				break;
   949 			case 0x040000:				// Bus Status Register 1 (read only)
   950 				handled = true;
   951 				break;
   952 			case 0x050000:				// Phone status
   953 				break;
   954 			case 0x060000:				// DMA Count
   955 				break;
   956 			case 0x070000:				// Line Printer Status Register
   957 				break;
   958 			case 0x080000:				// Real Time Clock
   959 				break;
   960 			case 0x090000:				// Phone registers
   961 				switch (address & 0x0FF000) {
   962 					case 0x090000:		// Handset relay
   963 					case 0x098000:
   964 						break;
   965 					case 0x091000:		// Line select 2
   966 					case 0x099000:
   967 						break;
   968 					case 0x092000:		// Hook relay 1
   969 					case 0x09A000:
   970 						break;
   971 					case 0x093000:		// Hook relay 2
   972 					case 0x09B000:
   973 						break;
   974 					case 0x094000:		// Line 1 hold
   975 					case 0x09C000:
   976 						break;
   977 					case 0x095000:		// Line 2 hold
   978 					case 0x09D000:
   979 						break;
   980 					case 0x096000:		// Line 1 A-lead
   981 					case 0x09E000:
   982 						break;
   983 					case 0x097000:		// Line 2 A-lead
   984 					case 0x09F000:
   985 						break;
   986 				}
   987 				break;
   988 			case 0x0A0000:				// Miscellaneous Control Register
   989 				break;
   990 			case 0x0B0000:				// TM/DIALWR
   991 				break;
   992 			case 0x0C0000:				// CSR
   993 				break;
   994 			case 0x0D0000:				// DMA Address Register
   995 				break;
   996 			case 0x0E0000:				// Disk Control Register
   997 				break;
   998 			case 0x0F0000:				// Line Printer Data Register
   999 				break;
  1001 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
  1002 		// I/O register space, zone B
  1003 		switch (address & 0xF00000) {
  1004 			case 0xC00000:				// Expansion slots
  1005 			case 0xD00000:
  1006 				switch (address & 0xFC0000) {
  1007 					case 0xC00000:		// Expansion slot 0
  1008 					case 0xC40000:		// Expansion slot 1
  1009 					case 0xC80000:		// Expansion slot 2
  1010 					case 0xCC0000:		// Expansion slot 3
  1011 					case 0xD00000:		// Expansion slot 4
  1012 					case 0xD40000:		// Expansion slot 5
  1013 					case 0xD80000:		// Expansion slot 6
  1014 					case 0xDC0000:		// Expansion slot 7
  1015 						fprintf(stderr, "NOTE: WR16 to expansion card space, addr=0x%08X, data=0x%04X\n", address, value);
  1016 						break;
  1018 				break;
  1019 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
  1020 			case 0xF00000:
  1021 				switch (address & 0x070000) {
  1022 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
  1023 						break;
  1024 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
  1025 						break;
  1026 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
  1027 						break;
  1028 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
  1029 						break;
  1030 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
  1031 						switch (address & 0x077000) {
  1032 							case 0x040000:		// [ef][4c][08]xxx ==> EE
  1033 								break;
  1034 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
  1035 								break;
  1036 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
  1037 								break;
  1038 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
  1039 								state.romlmap = ((value & 0x8000) == 0x8000);
  1040 								handled = true;
  1041 								break;
  1042 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
  1043 								break;
  1044 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
  1045 								break;
  1046 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
  1047 								break;
  1048 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
  1049 								break;
  1051 					case 0x050000:		// [ef][5d]xxxx ==> 8274
  1052 						break;
  1053 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
  1054 						switch (address & 0x07F000) {
  1055 							default:
  1056 								break;
  1058 						break;
  1059 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
  1060 						break;
  1065 	LOG_NOT_HANDLED_W(16);
  1068 /**
  1069  * @brief Write M68K memory, 8-bit
  1070  */
  1071 void m68k_write_memory_8(uint32_t address, uint32_t value)
  1073 	bool handled = false;
  1075 	// If ROMLMAP is set, force system to access ROM
  1076 	if (!state.romlmap)
  1077 		address |= 0x800000;
  1079 	// Check access permissions
  1080 	ACCESS_CHECK_WR(address, 8);
  1082 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
  1083 		// ROM access (read only!)
  1084 		handled = true;
  1085 	} else if (address <= (state.ram_size - 1)) {
  1086 		// RAM access
  1087 		WR8(state.ram, mapAddr(address, false), state.ram_size - 1, value);
  1088 		handled = true;
  1089 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
  1090 		// I/O register space, zone A
  1091 		switch (address & 0x0F0000) {
  1092 			case 0x000000:				// Map RAM access
  1093 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=%08X, data=%02X\n", address, value);
  1094 				WR8(state.map, address, 0x7FF, value);
  1095 				handled = true;
  1096 				break;
  1097 			case 0x010000:				// General Status Register
  1098 				handled = true;
  1099 				break;
  1100 			case 0x020000:				// Video RAM
  1101 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=%08X\n, data=0x%02X", address, value);
  1102 				WR8(state.vram, address, 0x7FFF, value);
  1103 				handled = true;
  1104 				break;
  1105 			case 0x030000:				// Bus Status Register 0
  1106 				handled = true;
  1107 				break;
  1108 			case 0x040000:				// Bus Status Register 1
  1109 				handled = true;
  1110 				break;
  1111 			case 0x050000:				// Phone status
  1112 				break;
  1113 			case 0x060000:				// DMA Count
  1114 				break;
  1115 			case 0x070000:				// Line Printer Status Register
  1116 				break;
  1117 			case 0x080000:				// Real Time Clock
  1118 				break;
  1119 			case 0x090000:				// Phone registers
  1120 				switch (address & 0x0FF000) {
  1121 					case 0x090000:		// Handset relay
  1122 					case 0x098000:
  1123 						break;
  1124 					case 0x091000:		// Line select 2
  1125 					case 0x099000:
  1126 						break;
  1127 					case 0x092000:		// Hook relay 1
  1128 					case 0x09A000:
  1129 						break;
  1130 					case 0x093000:		// Hook relay 2
  1131 					case 0x09B000:
  1132 						break;
  1133 					case 0x094000:		// Line 1 hold
  1134 					case 0x09C000:
  1135 						break;
  1136 					case 0x095000:		// Line 2 hold
  1137 					case 0x09D000:
  1138 						break;
  1139 					case 0x096000:		// Line 1 A-lead
  1140 					case 0x09E000:
  1141 						break;
  1142 					case 0x097000:		// Line 2 A-lead
  1143 					case 0x09F000:
  1144 						break;
  1146 				break;
  1147 			case 0x0A0000:				// Miscellaneous Control Register
  1148 				break;
  1149 			case 0x0B0000:				// TM/DIALWR
  1150 				break;
  1151 			case 0x0C0000:				// CSR
  1152 				break;
  1153 			case 0x0D0000:				// DMA Address Register
  1154 				break;
  1155 			case 0x0E0000:				// Disk Control Register
  1156 				break;
  1157 			case 0x0F0000:				// Line Printer Data Register
  1158 				break;
  1160 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
  1161 		// I/O register space, zone B
  1162 		switch (address & 0xF00000) {
  1163 			case 0xC00000:				// Expansion slots
  1164 			case 0xD00000:
  1165 				switch (address & 0xFC0000) {
  1166 					case 0xC00000:		// Expansion slot 0
  1167 					case 0xC40000:		// Expansion slot 1
  1168 					case 0xC80000:		// Expansion slot 2
  1169 					case 0xCC0000:		// Expansion slot 3
  1170 					case 0xD00000:		// Expansion slot 4
  1171 					case 0xD40000:		// Expansion slot 5
  1172 					case 0xD80000:		// Expansion slot 6
  1173 					case 0xDC0000:		// Expansion slot 7
  1174 						fprintf(stderr, "NOTE: WR8 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
  1175 						break;
  1177 				break;
  1178 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
  1179 			case 0xF00000:
  1180 				switch (address & 0x070000) {
  1181 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
  1182 						break;
  1183 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
  1184 						break;
  1185 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
  1186 						break;
  1187 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
  1188 						break;
  1189 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
  1190 						switch (address & 0x077000) {
  1191 							case 0x040000:		// [ef][4c][08]xxx ==> EE
  1192 								break;
  1193 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
  1194 								break;
  1195 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
  1196 								break;
  1197 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
  1198 								if ((address & 1) == 0)
  1199 									state.romlmap = ((value & 0x80) == 0x80);
  1200 								handled = true;
  1201 								break;
  1202 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
  1203 								break;
  1204 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
  1205 								break;
  1206 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
  1207 								break;
  1208 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
  1209 								break;
  1211 					case 0x050000:		// [ef][5d]xxxx ==> 8274
  1212 						break;
  1213 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
  1214 						switch (address & 0x07F000) {
  1215 							default:
  1216 								break;
  1218 						break;
  1219 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
  1220 						break;
  1221 					default:
  1222 						fprintf(stderr, "NOTE: WR8 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
  1223 						break;
  1228 	LOG_NOT_HANDLED_W(8);
  1232 // for the disassembler
  1233 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
  1234 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
  1235 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
  1238 /****************************
  1239  * blessed be thy main()...
  1240  ****************************/
  1242 int main(void)
  1244 	// copyright banner
  1245 	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
  1246 	printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
  1247 	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
  1248 	printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
  1249 	printf("Compiler: %s\n", VER_COMPILER);
  1250 	printf("CFLAGS: %s\n", VER_CFLAGS);
  1251 	printf("\n");
  1253 	// set up system state
  1254 	// 512K of RAM
  1255 	state_init(512*1024);
  1257 	// set up musashi and reset the CPU
  1258 	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
  1259 	m68k_pulse_reset();
  1261 	// Set up SDL
  1262 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
  1263 		printf("Could not initialise SDL: %s.\n", SDL_GetError());
  1264 		exit(EXIT_FAILURE);
  1267 	// Make sure SDL cleans up after itself
  1268 	atexit(SDL_Quit);
  1270 	// Set up the video display
  1271 	SDL_Surface *screen = NULL;
  1272 	if ((screen = SDL_SetVideoMode(720, 384, 8, SDL_SWSURFACE | SDL_ANYFORMAT)) == NULL) {
  1273 		printf("Could not find a suitable video mode: %s.\n", SDL_GetError());
  1274 		exit(EXIT_FAILURE);
  1276 	printf("Set %dx%d at %d bits-per-pixel mode\n\n", screen->w, screen->h, screen->format->BitsPerPixel);
  1277 	SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
  1279 	/***
  1280 	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
  1281 	 * around 60Hz (???), with a 60Hz periodic interrupt.
  1282 	 */
  1283 	const uint32_t TIMESLOT_FREQUENCY = 240;	// Hz
  1284 	const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
  1285 	const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
  1286 	uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
  1287 	uint32_t clock_cycles = 0;
  1288 	bool exitEmu = false;
  1289 	for (;;) {
  1290 		// Run the CPU for however many cycles we need to. CPU core clock is
  1291 		// 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
  1292 		// 41667 cycles per timeslot.
  1293 		clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
  1295 		// TODO: run DMA here
  1297 		// Is it time to run the 60Hz periodic interrupt yet?
  1298 		if (clock_cycles > CLOCKS_PER_60HZ) {
  1299 			// TODO: refresh screen
  1300 			// TODO: trigger periodic interrupt (if enabled)
  1301 			// decrement clock cycle counter, we've handled the intr.
  1302 			clock_cycles -= CLOCKS_PER_60HZ;
  1305 		// make sure frame rate is equal to real time
  1306 		uint32_t now = SDL_GetTicks();
  1307 		if (now < next_timeslot) {
  1308 			// timeslot finished early -- eat up some time
  1309 			SDL_Delay(next_timeslot - now);
  1310 		} else {
  1311 			// timeslot finished late -- skip ahead to gain time
  1312 			// TODO: if this happens a lot, we should let the user know
  1313 			// that their PC might not be fast enough...
  1314 			next_timeslot = now;
  1316 		// advance to the next timeslot
  1317 		next_timeslot += MILLISECS_PER_TIMESLOT;
  1319 		// if we've been asked to exit the emulator, then do so.
  1320 		if (exitEmu) break;
  1323 	// shut down and exit
  1324 	SDL_Quit();
  1326 	return 0;