src/main.c

Thu, 02 Dec 2010 20:58:12 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 02 Dec 2010 20:58:12 +0000
changeset 37
87662afa1d98
parent 36
746fb8d0653e
child 38
b948045ca964
permissions
-rw-r--r--

rework address-check logic

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