src/main.c

Thu, 02 Dec 2010 20:19:20 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 02 Dec 2010 20:19:20 +0000
changeset 35
391318413bb2
parent 34
e8ebd433270a
child 36
746fb8d0653e
permissions
-rw-r--r--

fix ROMLMAP handling

     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() do {									\
   152 		/* MEM_STATUS st; */									\
   153 		switch (checkMemoryAccess(address, true)) {				\
   154 			case MEM_ALLOWED:									\
   155 				/* Access allowed */							\
   156 				break;											\
   157 			case MEM_PAGEFAULT:									\
   158 				/* Page fault */								\
   159 				state.genstat = 0x8FFF;							\
   160 				m68k_pulse_bus_error();							\
   161 				return;											\
   162 			case MEM_UIE:										\
   163 				/* User access to memory above 4MB */			\
   164 				state.genstat = 0x9EFF;							\
   165 				m68k_pulse_bus_error();							\
   166 				return;											\
   167 			case MEM_KERNEL:									\
   168 			case MEM_PAGE_NO_WE:								\
   169 				/* kernel access or page not write enabled */	\
   170 				/* TODO: which regs need setting? */			\
   171 				m68k_pulse_bus_error();							\
   172 				return;											\
   173 		}														\
   174 	} while (false)
   176 /**
   177  * @brief Check memory access permissions for a read operation.
   178  * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   179  * 			gcc throws warnings when you have a return-with-value in a void
   180  * 			function, even if the return-with-value is completely unreachable.
   181  * 			Similarly it doesn't like it if you have a return without a value
   182  * 			in a non-void function, even if it's impossible to ever reach the
   183  * 			return-with-no-value. UGH!
   184  */
   185 #define ACCESS_CHECK_RD() do {									\
   186 		/* MEM_STATUS st; */									\
   187 		switch (checkMemoryAccess(address, false)) {			\
   188 			case MEM_ALLOWED:									\
   189 				/* Access allowed */							\
   190 				break;											\
   191 			case MEM_PAGEFAULT:									\
   192 				/* Page fault */								\
   193 				state.genstat = 0xCFFF;							\
   194 				m68k_pulse_bus_error();							\
   195 				return 0xFFFFFFFF;								\
   196 			case MEM_UIE:										\
   197 				/* User access to memory above 4MB */			\
   198 				state.genstat = 0xDEFF;							\
   199 				m68k_pulse_bus_error();							\
   200 				return 0xFFFFFFFF;								\
   201 			case MEM_KERNEL:									\
   202 			case MEM_PAGE_NO_WE:								\
   203 				/* kernel access or page not write enabled */	\
   204 				/* TODO: which regs need setting? */			\
   205 				m68k_pulse_bus_error();							\
   206 				return 0xFFFFFFFF;								\
   207 		}														\
   208 	} while (false)
   210 /**
   211  * @brief Read M68K memory, 32-bit
   212  */
   213 uint32_t m68k_read_memory_32(uint32_t address)
   214 {
   215 	uint32_t data = 0xFFFFFFFF;
   217 	// If ROMLMAP is set, force system to access ROM
   218 	if (!state.romlmap)
   219 		address |= 0x800000;
   221 	// Check access permissions
   222 	ACCESS_CHECK_RD();
   224 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   225 		// ROM access
   226 		data = RD32(state.rom, address, ROM_SIZE - 1);
   227 	} else if (address <= (state.ram_size - 1)) {
   228 		// RAM access
   229 		data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1);
   230 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   231 		// I/O register space, zone A
   232 		printf("RD32 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   233 		switch (address & 0x0F0000) {
   234 			case 0x000000:				// Map RAM access
   235 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
   236 				data = RD32(state.map, address, 0x7FF);
   237 				break;
   238 			case 0x010000:				// General Status Register
   239 				data = ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
   240 				break;
   241 			case 0x020000:				// Video RAM
   242 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
   243 				data = RD32(state.vram, address, 0x7FFF);
   244 				break;
   245 			case 0x030000:				// Bus Status Register 0
   246 				break;
   247 			case 0x040000:				// Bus Status Register 1
   248 				break;
   249 			case 0x050000:				// Phone status
   250 				break;
   251 			case 0x060000:				// DMA Count
   252 				break;
   253 			case 0x070000:				// Line Printer Status Register
   254 				break;
   255 			case 0x080000:				// Real Time Clock
   256 				break;
   257 			case 0x090000:				// Phone registers
   258 				switch (address & 0x0FF000) {
   259 					case 0x090000:		// Handset relay
   260 					case 0x098000:
   261 						break;
   262 					case 0x091000:		// Line select 2
   263 					case 0x099000:
   264 						break;
   265 					case 0x092000:		// Hook relay 1
   266 					case 0x09A000:
   267 						break;
   268 					case 0x093000:		// Hook relay 2
   269 					case 0x09B000:
   270 						break;
   271 					case 0x094000:		// Line 1 hold
   272 					case 0x09C000:
   273 						break;
   274 					case 0x095000:		// Line 2 hold
   275 					case 0x09D000:
   276 						break;
   277 					case 0x096000:		// Line 1 A-lead
   278 					case 0x09E000:
   279 						break;
   280 					case 0x097000:		// Line 2 A-lead
   281 					case 0x09F000:
   282 						break;
   283 				}
   284 				break;
   285 			case 0x0A0000:				// Miscellaneous Control Register
   286 				break;
   287 			case 0x0B0000:				// TM/DIALWR
   288 				break;
   289 			case 0x0C0000:				// CSR
   290 				break;
   291 			case 0x0D0000:				// DMA Address Register
   292 				break;
   293 			case 0x0E0000:				// Disk Control Register
   294 				break;
   295 			case 0x0F0000:				// Line Printer Data Register
   296 				break;
   297 		}
   298 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   299 		// I/O register space, zone B
   300 		printf("RD32 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   301 		switch (address & 0xF00000) {
   302 			case 0xC00000:				// Expansion slots
   303 			case 0xD00000:
   304 				switch (address & 0xFC0000) {
   305 					case 0xC00000:		// Expansion slot 0
   306 					case 0xC40000:		// Expansion slot 1
   307 					case 0xC80000:		// Expansion slot 2
   308 					case 0xCC0000:		// Expansion slot 3
   309 					case 0xD00000:		// Expansion slot 4
   310 					case 0xD40000:		// Expansion slot 5
   311 					case 0xD80000:		// Expansion slot 6
   312 					case 0xDC0000:		// Expansion slot 7
   313 						fprintf(stderr, "NOTE: RD32 from expansion card space, addr=0x%08X\n", address);
   314 						break;
   315 				}
   316 				break;
   317 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   318 			case 0xF00000:
   319 				switch (address & 0x070000) {
   320 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   321 						break;
   322 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   323 						break;
   324 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   325 						break;
   326 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   327 						break;
   328 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   329 						switch (address & 0x077000) {
   330 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   331 								break;
   332 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   333 								break;
   334 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   335 								break;
   336 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   337 								break;
   338 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   339 								break;
   340 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   341 								break;
   342 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   343 								break;
   344 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   345 								break;
   346 						}
   347 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   348 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   349 						switch (address & 0x07F000) {
   350 							default:
   351 								break;
   352 						}
   353 						break;
   354 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   355 					default:
   356 						fprintf(stderr, "NOTE: RD32 from undefined E/F-block address 0x%08X", address);
   357 				}
   358 		}
   359 	}
   360 	return data;
   361 }
   363 /**
   364  * @brief Read M68K memory, 16-bit
   365  */
   366 uint32_t m68k_read_memory_16(uint32_t address)
   367 {
   368 	uint16_t data = 0xFFFF;
   370 	// If ROMLMAP is set, force system to access ROM
   371 	if (!state.romlmap)
   372 		address |= 0x800000;
   374 	// Check access permissions
   375 	ACCESS_CHECK_RD();
   377 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   378 		// ROM access
   379 		data = RD16(state.rom, address, ROM_SIZE - 1);
   380 	} else if (address <= (state.ram_size - 1)) {
   381 		// RAM access
   382 		data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1);
   383 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   384 		// I/O register space, zone A
   385 		printf("RD16 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   386 		switch (address & 0x0F0000) {
   387 			case 0x000000:				// Map RAM access
   388 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
   389 				data = RD16(state.map, address, 0x7FF);
   390 				break;
   391 			case 0x010000:				// General Status Register
   392 				data = state.genstat;
   393 				break;
   394 			case 0x020000:				// Video RAM
   395 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
   396 				data = RD16(state.vram, address, 0x7FFF);
   397 				break;
   398 			case 0x030000:				// Bus Status Register 0
   399 				break;
   400 			case 0x040000:				// Bus Status Register 1
   401 				break;
   402 			case 0x050000:				// Phone status
   403 				break;
   404 			case 0x060000:				// DMA Count
   405 				break;
   406 			case 0x070000:				// Line Printer Status Register
   407 				break;
   408 			case 0x080000:				// Real Time Clock
   409 				break;
   410 			case 0x090000:				// Phone registers
   411 				switch (address & 0x0FF000) {
   412 					case 0x090000:		// Handset relay
   413 					case 0x098000:
   414 						break;
   415 					case 0x091000:		// Line select 2
   416 					case 0x099000:
   417 						break;
   418 					case 0x092000:		// Hook relay 1
   419 					case 0x09A000:
   420 						break;
   421 					case 0x093000:		// Hook relay 2
   422 					case 0x09B000:
   423 						break;
   424 					case 0x094000:		// Line 1 hold
   425 					case 0x09C000:
   426 						break;
   427 					case 0x095000:		// Line 2 hold
   428 					case 0x09D000:
   429 						break;
   430 					case 0x096000:		// Line 1 A-lead
   431 					case 0x09E000:
   432 						break;
   433 					case 0x097000:		// Line 2 A-lead
   434 					case 0x09F000:
   435 						break;
   436 				}
   437 				break;
   438 			case 0x0A0000:				// Miscellaneous Control Register
   439 				break;
   440 			case 0x0B0000:				// TM/DIALWR
   441 				break;
   442 			case 0x0C0000:				// CSR
   443 				break;
   444 			case 0x0D0000:				// DMA Address Register
   445 				break;
   446 			case 0x0E0000:				// Disk Control Register
   447 				break;
   448 			case 0x0F0000:				// Line Printer Data Register
   449 				break;
   450 		}
   451 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   452 		// I/O register space, zone B
   453 		printf("RD16 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   454 		switch (address & 0xF00000) {
   455 			case 0xC00000:				// Expansion slots
   456 			case 0xD00000:
   457 				switch (address & 0xFC0000) {
   458 					case 0xC00000:		// Expansion slot 0
   459 					case 0xC40000:		// Expansion slot 1
   460 					case 0xC80000:		// Expansion slot 2
   461 					case 0xCC0000:		// Expansion slot 3
   462 					case 0xD00000:		// Expansion slot 4
   463 					case 0xD40000:		// Expansion slot 5
   464 					case 0xD80000:		// Expansion slot 6
   465 					case 0xDC0000:		// Expansion slot 7
   466 						fprintf(stderr, "NOTE: RD16 from expansion card space, addr=0x%08X\n", address);
   467 						break;
   468 				}
   469 				break;
   470 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   471 			case 0xF00000:
   472 				switch (address & 0x070000) {
   473 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   474 						break;
   475 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   476 						break;
   477 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   478 						break;
   479 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   480 						break;
   481 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   482 						switch (address & 0x077000) {
   483 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   484 								break;
   485 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   486 								break;
   487 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   488 								break;
   489 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   490 								break;
   491 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   492 								break;
   493 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   494 								break;
   495 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   496 								break;
   497 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   498 								break;
   499 						}
   500 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   501 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   502 						switch (address & 0x07F000) {
   503 							default:
   504 								break;
   505 						}
   506 						break;
   507 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   508 					default:
   509 						fprintf(stderr, "NOTE: RD16 from undefined E/F-block address 0x%08X", address);
   510 				}
   511 		}
   512 	}
   513 	return data;
   514 }
   516 /**
   517  * @brief Read M68K memory, 8-bit
   518  */
   519 uint32_t m68k_read_memory_8(uint32_t address)
   520 {
   521 	uint8_t data = 0xFF;
   523 	// If ROMLMAP is set, force system to access ROM
   524 	if (!state.romlmap)
   525 		address |= 0x800000;
   527 	// Check access permissions
   528 	ACCESS_CHECK_RD();
   530 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   531 		// ROM access
   532 		data = RD8(state.rom, address, ROM_SIZE - 1);
   533 	} else if (address <= (state.ram_size - 1)) {
   534 		// RAM access
   535 		data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1);
   536 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   537 		// I/O register space, zone A
   538 		printf("RD8 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   539 		switch (address & 0x0F0000) {
   540 			case 0x000000:				// Map RAM access
   541 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
   542 				data = RD8(state.map, address, 0x7FF);
   543 				break;
   544 			case 0x010000:				// General Status Register
   545 				if ((address & 1) == 0)
   546 					data = (state.genstat >> 8) & 0xff;
   547 				else
   548 					data = (state.genstat)      & 0xff;
   549 				break;
   550 			case 0x020000:				// Video RAM
   551 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
   552 				data = RD8(state.vram, address, 0x7FFF);
   553 				break;
   554 			case 0x030000:				// Bus Status Register 0
   555 				break;
   556 			case 0x040000:				// Bus Status Register 1
   557 				break;
   558 			case 0x050000:				// Phone status
   559 				break;
   560 			case 0x060000:				// DMA Count
   561 				break;
   562 			case 0x070000:				// Line Printer Status Register
   563 				break;
   564 			case 0x080000:				// Real Time Clock
   565 				break;
   566 			case 0x090000:				// Phone registers
   567 				switch (address & 0x0FF000) {
   568 					case 0x090000:		// Handset relay
   569 					case 0x098000:
   570 						break;
   571 					case 0x091000:		// Line select 2
   572 					case 0x099000:
   573 						break;
   574 					case 0x092000:		// Hook relay 1
   575 					case 0x09A000:
   576 						break;
   577 					case 0x093000:		// Hook relay 2
   578 					case 0x09B000:
   579 						break;
   580 					case 0x094000:		// Line 1 hold
   581 					case 0x09C000:
   582 						break;
   583 					case 0x095000:		// Line 2 hold
   584 					case 0x09D000:
   585 						break;
   586 					case 0x096000:		// Line 1 A-lead
   587 					case 0x09E000:
   588 						break;
   589 					case 0x097000:		// Line 2 A-lead
   590 					case 0x09F000:
   591 						break;
   592 				}
   593 				break;
   594 			case 0x0A0000:				// Miscellaneous Control Register
   595 				break;
   596 			case 0x0B0000:				// TM/DIALWR
   597 				break;
   598 			case 0x0C0000:				// CSR
   599 				break;
   600 			case 0x0D0000:				// DMA Address Register
   601 				break;
   602 			case 0x0E0000:				// Disk Control Register
   603 				break;
   604 			case 0x0F0000:				// Line Printer Data Register
   605 				break;
   606 		}
   607 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   608 		// I/O register space, zone B
   609 		printf("RD8 0x%08X ==> ??? %s\n", address, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   610 		switch (address & 0xF00000) {
   611 			case 0xC00000:				// Expansion slots
   612 			case 0xD00000:
   613 				switch (address & 0xFC0000) {
   614 					case 0xC00000:		// Expansion slot 0
   615 					case 0xC40000:		// Expansion slot 1
   616 					case 0xC80000:		// Expansion slot 2
   617 					case 0xCC0000:		// Expansion slot 3
   618 					case 0xD00000:		// Expansion slot 4
   619 					case 0xD40000:		// Expansion slot 5
   620 					case 0xD80000:		// Expansion slot 6
   621 					case 0xDC0000:		// Expansion slot 7
   622 						fprintf(stderr, "NOTE: RD8 from expansion card space, addr=0x%08X\n", address);
   623 						break;
   624 				}
   625 				break;
   626 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   627 			case 0xF00000:
   628 				switch (address & 0x070000) {
   629 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   630 						break;
   631 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   632 						break;
   633 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   634 						break;
   635 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   636 						break;
   637 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   638 						switch (address & 0x077000) {
   639 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   640 								break;
   641 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   642 								break;
   643 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   644 								break;
   645 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   646 								break;
   647 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   648 								break;
   649 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   650 								break;
   651 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   652 								break;
   653 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   654 								break;
   655 						}
   656 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   657 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   658 						switch (address & 0x07F000) {
   659 							default:
   660 								break;
   661 						}
   662 						break;
   663 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   664 					default:
   665 						fprintf(stderr, "NOTE: RD8 from undefined E/F-block address 0x%08X", address);
   666 				}
   667 		}
   668 	}
   669 	return data;
   670 }
   672 /**
   673  * @brief Write M68K memory, 32-bit
   674  */
   675 void m68k_write_memory_32(uint32_t address, uint32_t value)
   676 {
   677 	// If ROMLMAP is set, force system to access ROM
   678 	if (!state.romlmap)
   679 		address |= 0x800000;
   681 	// Check access permissions
   682 	ACCESS_CHECK_WR();
   684 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   685 		// ROM access
   686 		WR32(state.rom, address, ROM_SIZE - 1, value);
   687 	} else if (address <= (state.ram_size - 1)) {
   688 		// RAM access
   689 		WR32(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   690 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   691 		// I/O register space, zone A
   692 		printf("WR32 0x%08X ==> 0x%08X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   693 		switch (address & 0x0F0000) {
   694 			case 0x000000:				// Map RAM access
   695 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   696 				WR32(state.map, address, 0x7FF, value);
   697 				break;
   698 			case 0x010000:				// General Status Register
   699 				state.genstat = (value & 0xffff);
   700 				break;
   701 			case 0x020000:				// Video RAM
   702 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   703 				WR32(state.vram, address, 0x7FFF, value);
   704 				break;
   705 			case 0x030000:				// Bus Status Register 0
   706 				break;
   707 			case 0x040000:				// Bus Status Register 1
   708 				break;
   709 			case 0x050000:				// Phone status
   710 				break;
   711 			case 0x060000:				// DMA Count
   712 				break;
   713 			case 0x070000:				// Line Printer Status Register
   714 				break;
   715 			case 0x080000:				// Real Time Clock
   716 				break;
   717 			case 0x090000:				// Phone registers
   718 				switch (address & 0x0FF000) {
   719 					case 0x090000:		// Handset relay
   720 					case 0x098000:
   721 						break;
   722 					case 0x091000:		// Line select 2
   723 					case 0x099000:
   724 						break;
   725 					case 0x092000:		// Hook relay 1
   726 					case 0x09A000:
   727 						break;
   728 					case 0x093000:		// Hook relay 2
   729 					case 0x09B000:
   730 						break;
   731 					case 0x094000:		// Line 1 hold
   732 					case 0x09C000:
   733 						break;
   734 					case 0x095000:		// Line 2 hold
   735 					case 0x09D000:
   736 						break;
   737 					case 0x096000:		// Line 1 A-lead
   738 					case 0x09E000:
   739 						break;
   740 					case 0x097000:		// Line 2 A-lead
   741 					case 0x09F000:
   742 						break;
   743 				}
   744 				break;
   745 			case 0x0A0000:				// Miscellaneous Control Register
   746 				break;
   747 			case 0x0B0000:				// TM/DIALWR
   748 				break;
   749 			case 0x0C0000:				// CSR
   750 				break;
   751 			case 0x0D0000:				// DMA Address Register
   752 				break;
   753 			case 0x0E0000:				// Disk Control Register
   754 				break;
   755 			case 0x0F0000:				// Line Printer Data Register
   756 				break;
   757 		}
   758 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   759 		// I/O register space, zone B
   760 		printf("WR32 0x%08X ==> 0x%08X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   761 		switch (address & 0xF00000) {
   762 			case 0xC00000:				// Expansion slots
   763 			case 0xD00000:
   764 				switch (address & 0xFC0000) {
   765 					case 0xC00000:		// Expansion slot 0
   766 					case 0xC40000:		// Expansion slot 1
   767 					case 0xC80000:		// Expansion slot 2
   768 					case 0xCC0000:		// Expansion slot 3
   769 					case 0xD00000:		// Expansion slot 4
   770 					case 0xD40000:		// Expansion slot 5
   771 					case 0xD80000:		// Expansion slot 6
   772 					case 0xDC0000:		// Expansion slot 7
   773 						fprintf(stderr, "NOTE: WR32 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
   774 						break;
   775 				}
   776 				break;
   777 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   778 			case 0xF00000:
   779 				switch (address & 0x070000) {
   780 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   781 						break;
   782 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   783 						break;
   784 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   785 						break;
   786 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   787 						break;
   788 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   789 						switch (address & 0x077000) {
   790 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   791 								break;
   792 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   793 								break;
   794 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   795 								break;
   796 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   797 								state.romlmap = ((value & 0x8000) == 0x8000);
   798 								break;
   799 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   800 								break;
   801 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   802 								break;
   803 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   804 								break;
   805 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   806 								break;
   807 						}
   808 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   809 						break;
   810 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   811 						switch (address & 0x07F000) {
   812 							default:
   813 								break;
   814 						}
   815 						break;
   816 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   817 						break;
   818 					default:
   819 						fprintf(stderr, "NOTE: WR32 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
   820 				}
   821 		}
   822 	}
   823 }
   825 /**
   826  * @brief Write M68K memory, 16-bit
   827  */
   828 void m68k_write_memory_16(uint32_t address, uint32_t value)
   829 {
   830 	// If ROMLMAP is set, force system to access ROM
   831 	if (!state.romlmap)
   832 		address |= 0x800000;
   834 	// Check access permissions
   835 	ACCESS_CHECK_WR();
   837 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   838 		// ROM access
   839 		WR16(state.rom, address, ROM_SIZE - 1, value);
   840 	} else if (address <= (state.ram_size - 1)) {
   841 		// RAM access
   842 		WR16(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   843 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   844 		// I/O register space, zone A
   845 		printf("WR16 0x%08X ==> 0x%04X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   846 		switch (address & 0x0F0000) {
   847 			case 0x000000:				// Map RAM access
   848 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   849 				WR16(state.map, address, 0x7FF, value);
   850 				break;
   851 			case 0x010000:				// General Status Register
   852 				state.genstat = (value & 0xffff);
   853 				break;
   854 			case 0x020000:				// Video RAM
   855 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   856 				WR16(state.vram, address, 0x7FFF, value);
   857 				break;
   858 			case 0x030000:				// Bus Status Register 0
   859 				break;
   860 			case 0x040000:				// Bus Status Register 1
   861 				break;
   862 			case 0x050000:				// Phone status
   863 				break;
   864 			case 0x060000:				// DMA Count
   865 				break;
   866 			case 0x070000:				// Line Printer Status Register
   867 				break;
   868 			case 0x080000:				// Real Time Clock
   869 				break;
   870 			case 0x090000:				// Phone registers
   871 				switch (address & 0x0FF000) {
   872 					case 0x090000:		// Handset relay
   873 					case 0x098000:
   874 						break;
   875 					case 0x091000:		// Line select 2
   876 					case 0x099000:
   877 						break;
   878 					case 0x092000:		// Hook relay 1
   879 					case 0x09A000:
   880 						break;
   881 					case 0x093000:		// Hook relay 2
   882 					case 0x09B000:
   883 						break;
   884 					case 0x094000:		// Line 1 hold
   885 					case 0x09C000:
   886 						break;
   887 					case 0x095000:		// Line 2 hold
   888 					case 0x09D000:
   889 						break;
   890 					case 0x096000:		// Line 1 A-lead
   891 					case 0x09E000:
   892 						break;
   893 					case 0x097000:		// Line 2 A-lead
   894 					case 0x09F000:
   895 						break;
   896 				}
   897 				break;
   898 			case 0x0A0000:				// Miscellaneous Control Register
   899 				break;
   900 			case 0x0B0000:				// TM/DIALWR
   901 				break;
   902 			case 0x0C0000:				// CSR
   903 				break;
   904 			case 0x0D0000:				// DMA Address Register
   905 				break;
   906 			case 0x0E0000:				// Disk Control Register
   907 				break;
   908 			case 0x0F0000:				// Line Printer Data Register
   909 				break;
   910 		}
   911 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   912 		// I/O register space, zone B
   913 		printf("WR16 0x%08X ==> 0x%04X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   914 		switch (address & 0xF00000) {
   915 			case 0xC00000:				// Expansion slots
   916 			case 0xD00000:
   917 				switch (address & 0xFC0000) {
   918 					case 0xC00000:		// Expansion slot 0
   919 					case 0xC40000:		// Expansion slot 1
   920 					case 0xC80000:		// Expansion slot 2
   921 					case 0xCC0000:		// Expansion slot 3
   922 					case 0xD00000:		// Expansion slot 4
   923 					case 0xD40000:		// Expansion slot 5
   924 					case 0xD80000:		// Expansion slot 6
   925 					case 0xDC0000:		// Expansion slot 7
   926 						fprintf(stderr, "NOTE: WR16 to expansion card space, addr=0x%08X, data=0x%04X\n", address, value);
   927 						break;
   928 				}
   929 				break;
   930 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   931 			case 0xF00000:
   932 				switch (address & 0x070000) {
   933 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   934 						break;
   935 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   936 						break;
   937 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   938 						break;
   939 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   940 						break;
   941 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   942 						switch (address & 0x077000) {
   943 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   944 								break;
   945 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
   946 								break;
   947 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   948 								break;
   949 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   950 								state.romlmap = ((value & 0x8000) == 0x8000);
   951 								break;
   952 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   953 								break;
   954 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   955 								break;
   956 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   957 								break;
   958 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   959 								break;
   960 						}
   961 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   962 						break;
   963 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   964 						switch (address & 0x07F000) {
   965 							default:
   966 								break;
   967 						}
   968 						break;
   969 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   970 						break;
   971 					default:
   972 						fprintf(stderr, "NOTE: WR32 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
   973 				}
   974 		}
   975 	}
   976 }
   978 /**
   979  * @brief Write M68K memory, 8-bit
   980  */
   981 void m68k_write_memory_8(uint32_t address, uint32_t value)
   982 {
   983 	// If ROMLMAP is set, force system to access ROM
   984 	if (!state.romlmap)
   985 		address |= 0x800000;
   987 	// Check access permissions
   988 	ACCESS_CHECK_WR();
   990 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   991 		// ROM access
   992 		WR8(state.rom, address, ROM_SIZE - 1, value);
   993 	} else if (address <= (state.ram_size - 1)) {
   994 		// RAM access
   995 		WR8(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   996 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   997 		// I/O register space, zone A
   998 		printf("WR8 0x%08X ==> %02X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
   999 		switch (address & 0x0F0000) {
  1000 			case 0x000000:				// Map RAM access
  1001 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=%08X, data=%02X\n", address, value);
  1002 				WR8(state.map, address, 0x7FF, value);
  1003 				break;
  1004 			case 0x010000:				// General Status Register
  1005 				state.genstat = (value & 0xffff);
  1006 				break;
  1007 			case 0x020000:				// Video RAM
  1008 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=%08X\n, data=0x%02X", address, value);
  1009 				WR8(state.vram, address, 0x7FFF, value);
  1010 				break;
  1011 			case 0x030000:				// Bus Status Register 0
  1012 				break;
  1013 			case 0x040000:				// Bus Status Register 1
  1014 				break;
  1015 			case 0x050000:				// Phone status
  1016 				break;
  1017 			case 0x060000:				// DMA Count
  1018 				break;
  1019 			case 0x070000:				// Line Printer Status Register
  1020 				break;
  1021 			case 0x080000:				// Real Time Clock
  1022 				break;
  1023 			case 0x090000:				// Phone registers
  1024 				switch (address & 0x0FF000) {
  1025 					case 0x090000:		// Handset relay
  1026 					case 0x098000:
  1027 						break;
  1028 					case 0x091000:		// Line select 2
  1029 					case 0x099000:
  1030 						break;
  1031 					case 0x092000:		// Hook relay 1
  1032 					case 0x09A000:
  1033 						break;
  1034 					case 0x093000:		// Hook relay 2
  1035 					case 0x09B000:
  1036 						break;
  1037 					case 0x094000:		// Line 1 hold
  1038 					case 0x09C000:
  1039 						break;
  1040 					case 0x095000:		// Line 2 hold
  1041 					case 0x09D000:
  1042 						break;
  1043 					case 0x096000:		// Line 1 A-lead
  1044 					case 0x09E000:
  1045 						break;
  1046 					case 0x097000:		// Line 2 A-lead
  1047 					case 0x09F000:
  1048 						break;
  1050 				break;
  1051 			case 0x0A0000:				// Miscellaneous Control Register
  1052 				break;
  1053 			case 0x0B0000:				// TM/DIALWR
  1054 				break;
  1055 			case 0x0C0000:				// CSR
  1056 				break;
  1057 			case 0x0D0000:				// DMA Address Register
  1058 				break;
  1059 			case 0x0E0000:				// Disk Control Register
  1060 				break;
  1061 			case 0x0F0000:				// Line Printer Data Register
  1062 				break;
  1064 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
  1065 		// I/O register space, zone B
  1066 		printf("WR8 0x%08X ==> 0x%08X %s\n", address, value, m68k_get_reg(NULL, M68K_REG_SR) & 0x2000 ? "[SV]" : "");
  1067 		switch (address & 0xF00000) {
  1068 			case 0xC00000:				// Expansion slots
  1069 			case 0xD00000:
  1070 				switch (address & 0xFC0000) {
  1071 					case 0xC00000:		// Expansion slot 0
  1072 					case 0xC40000:		// Expansion slot 1
  1073 					case 0xC80000:		// Expansion slot 2
  1074 					case 0xCC0000:		// Expansion slot 3
  1075 					case 0xD00000:		// Expansion slot 4
  1076 					case 0xD40000:		// Expansion slot 5
  1077 					case 0xD80000:		// Expansion slot 6
  1078 					case 0xDC0000:		// Expansion slot 7
  1079 						fprintf(stderr, "NOTE: WR8 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
  1080 						break;
  1082 				break;
  1083 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
  1084 			case 0xF00000:
  1085 				switch (address & 0x070000) {
  1086 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
  1087 						break;
  1088 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
  1089 						break;
  1090 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
  1091 						break;
  1092 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
  1093 						break;
  1094 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
  1095 						switch (address & 0x077000) {
  1096 							case 0x040000:		// [ef][4c][08]xxx ==> EE
  1097 								break;
  1098 							case 0x041000:		// [ef][4c][19]xxx ==> P1E
  1099 								break;
  1100 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
  1101 								break;
  1102 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
  1103 								if ((address & 1) == 0)
  1104 								state.romlmap = ((value & 0x8000) == 0x8000);
  1105 								break;
  1106 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
  1107 								break;
  1108 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
  1109 								break;
  1110 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
  1111 								break;
  1112 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
  1113 								break;
  1115 					case 0x050000:		// [ef][5d]xxxx ==> 8274
  1116 						break;
  1117 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
  1118 						switch (address & 0x07F000) {
  1119 							default:
  1120 								break;
  1122 						break;
  1123 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
  1124 						break;
  1125 					default:
  1126 						fprintf(stderr, "NOTE: WR8 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
  1127 						break;
  1134 // for the disassembler
  1135 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
  1136 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
  1137 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
  1140 /****************************
  1141  * blessed be thy main()...
  1142  ****************************/
  1144 int main(void)
  1146 	// copyright banner
  1147 	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
  1148 	printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
  1149 	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
  1150 	printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
  1151 	printf("Compiler: %s\n", VER_COMPILER);
  1152 	printf("CFLAGS: %s\n", VER_CFLAGS);
  1153 	printf("\n");
  1155 	// set up system state
  1156 	// 512K of RAM
  1157 	state_init(512*1024);
  1159 	// set up musashi and reset the CPU
  1160 	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
  1161 	m68k_pulse_reset();
  1163 	// Set up SDL
  1164 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
  1165 		printf("Could not initialise SDL: %s.\n", SDL_GetError());
  1166 		exit(EXIT_FAILURE);
  1169 	// Make sure SDL cleans up after itself
  1170 	atexit(SDL_Quit);
  1172 	// Set up the video display
  1173 	SDL_Surface *screen = NULL;
  1174 	if ((screen = SDL_SetVideoMode(720, 384, 8, SDL_SWSURFACE | SDL_ANYFORMAT)) == NULL) {
  1175 		printf("Could not find a suitable video mode: %s.\n", SDL_GetError());
  1176 		exit(EXIT_FAILURE);
  1178 	printf("Set %dx%d at %d bits-per-pixel mode\n\n", screen->w, screen->h, screen->format->BitsPerPixel);
  1179 	SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee");
  1181 	/***
  1182 	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
  1183 	 * around 60Hz (???), with a 60Hz periodic interrupt.
  1184 	 */
  1185 	const uint32_t TIMESLOT_FREQUENCY = 240;	// Hz
  1186 	const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
  1187 	const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
  1188 	uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
  1189 	uint32_t clock_cycles = 0;
  1190 	bool exitEmu = false;
  1191 	for (;;) {
  1192 		// Run the CPU for however many cycles we need to. CPU core clock is
  1193 		// 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
  1194 		// 41667 cycles per timeslot.
  1195 		clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
  1197 		// TODO: run DMA here
  1199 		// Is it time to run the 60Hz periodic interrupt yet?
  1200 		if (clock_cycles > CLOCKS_PER_60HZ) {
  1201 			// TODO: refresh screen
  1202 			// TODO: trigger periodic interrupt (if enabled)
  1203 			// decrement clock cycle counter, we've handled the intr.
  1204 			clock_cycles -= CLOCKS_PER_60HZ;
  1207 		// make sure frame rate is equal to real time
  1208 		uint32_t now = SDL_GetTicks();
  1209 		if (now < next_timeslot) {
  1210 			// timeslot finished early -- eat up some time
  1211 			SDL_Delay(next_timeslot - now);
  1212 		} else {
  1213 			// timeslot finished late -- skip ahead to gain time
  1214 			// TODO: if this happens a lot, we should let the user know
  1215 			// that their PC might not be fast enough...
  1216 			next_timeslot = now;
  1218 		// advance to the next timeslot
  1219 		next_timeslot += MILLISECS_PER_TIMESLOT;
  1221 		// if we've been asked to exit the emulator, then do so.
  1222 		if (exitEmu) break;
  1225 	// shut down and exit
  1226 	SDL_Quit();
  1228 	return 0;