src/memory.c

Mon, 06 Dec 2010 01:43:04 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 06 Dec 2010 01:43:04 +0000
changeset 54
57c6ef81ae81
parent 53
e1693c4b8a0c
child 55
ba6b8e570062
child 76
2ef98ea1e944
permissions
-rw-r--r--

fix side-select bug in WDC FDC driver, was causing all reads to occur on side0... now the Loader boots!

Loader will boot, but immediately gives up on the floppy drive... Not sure why.

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <stdint.h>
     4 #include <stdbool.h>
     5 #include "musashi/m68k.h"
     6 #include "state.h"
     7 #include "memory.h"
     9 /******************
    10  * Memory mapping
    11  ******************/
    13 #define MAPRAM(addr) (((uint16_t)state.map[addr*2] << 8) + ((uint16_t)state.map[(addr*2)+1]))
    15 uint32_t mapAddr(uint32_t addr, bool writing)
    16 {
    17 	if (addr < 0x400000) {
    18 		// RAM access. Check against the Map RAM
    19 		// Start by getting the original page address
    20 		uint16_t page = (addr >> 12) & 0x3FF;
    22 		// Look it up in the map RAM and get the physical page address
    23 		uint32_t new_page_addr = MAPRAM(page) & 0x3FF;
    25 		// Update the Page Status bits
    26 		uint8_t pagebits = (MAPRAM(page) >> 13) & 0x03;
    27 		if (pagebits != 0) {
    28 			if (writing)
    29 				state.map[page*2] |= 0x60;		// Page written to (dirty)
    30 			else
    31 				state.map[page*2] |= 0x40;		// Page accessed but not written
    32 		}
    34 		// Return the address with the new physical page spliced in
    35 		return (new_page_addr << 12) + (addr & 0xFFF);
    36 	} else {
    37 		// I/O, VRAM or MapRAM space; no mapping is performed or required
    38 		// TODO: assert here?
    39 		return addr;
    40 	}
    41 }
    43 MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing)
    44 {
    45 	// Are we in Supervisor mode?
    46 	if (m68k_get_reg(NULL, M68K_REG_SR) & 0x2000)
    47 		// Yes. We can do anything we like.
    48 		return MEM_ALLOWED;
    50 	// If we're here, then we must be in User mode.
    51 	// Check that the user didn't access memory outside of the RAM area
    52 	if (addr >= 0x400000)
    53 		return MEM_UIE;
    55 	// This leaves us with Page Fault checking. Get the page bits for this page.
    56 	uint16_t page = (addr >> 12) & 0x3FF;
    57 	uint8_t pagebits = (MAPRAM(page) >> 13) & 0x07;
    59 	// Check page is present
    60 	if ((pagebits & 0x03) == 0)
    61 		return MEM_PAGEFAULT;
    63 	// User attempt to access the kernel
    64 	// A19, A20, A21, A22 low (kernel access): RAM addr before paging; not in Supervisor mode
    65 	if (((addr >> 19) & 0x0F) == 0)
    66 		return MEM_KERNEL;
    68 	// Check page is write enabled
    69 	if ((pagebits & 0x04) == 0)
    70 		return MEM_PAGE_NO_WE;
    72 	// Page access allowed.
    73 	return MEM_ALLOWED;
    74 }
    76 #undef MAPRAM
    79 /********************************************************
    80  * m68k memory read/write support functions for Musashi
    81  ********************************************************/
    83 /**
    84  * @brief	Check memory access permissions for a write operation.
    85  * @note	This used to be a single macro (merged with ACCESS_CHECK_RD), but
    86  * 			gcc throws warnings when you have a return-with-value in a void
    87  * 			function, even if the return-with-value is completely unreachable.
    88  * 			Similarly it doesn't like it if you have a return without a value
    89  * 			in a non-void function, even if it's impossible to ever reach the
    90  * 			return-with-no-value. UGH!
    91  */
    92 #define ACCESS_CHECK_WR(address, bits) do {							\
    93 		bool fault = false;											\
    94 		/* MEM_STATUS st; */										\
    95 		switch (checkMemoryAccess(address, true)) {					\
    96 			case MEM_ALLOWED:										\
    97 				/* Access allowed */								\
    98 				break;												\
    99 			case MEM_PAGEFAULT:										\
   100 				/* Page fault */									\
   101 				state.genstat = 0x8BFF | (state.pie ? 0x0400 : 0);	\
   102 				fault = true;										\
   103 				break;												\
   104 			case MEM_UIE:											\
   105 				/* User access to memory above 4MB */				\
   106 				state.genstat = 0x9AFF | (state.pie ? 0x0400 : 0);	\
   107 				fault = true;										\
   108 				break;												\
   109 			case MEM_KERNEL:										\
   110 			case MEM_PAGE_NO_WE:									\
   111 				/* kernel access or page not write enabled */		\
   112 				/* TODO: which regs need setting? */				\
   113 				fault = true;										\
   114 				break;												\
   115 		}															\
   116 																	\
   117 		if (fault) {												\
   118 			if (bits >= 16)											\
   119 				state.bsr0 = 0x7F00;								\
   120 			else													\
   121 				state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00;		\
   122 			state.bsr0 |= (address >> 16);							\
   123 			state.bsr1 = address & 0xffff;							\
   124 			printf("ERR: BusError WR\n");							\
   125 			m68k_pulse_bus_error();									\
   126 			return;													\
   127 		}															\
   128 	} while (false)
   130 /**
   131  * @brief Check memory access permissions for a read operation.
   132  * @note	This used to be a single macro (merged with ACCESS_CHECK_WR), but
   133  * 			gcc throws warnings when you have a return-with-value in a void
   134  * 			function, even if the return-with-value is completely unreachable.
   135  * 			Similarly it doesn't like it if you have a return without a value
   136  * 			in a non-void function, even if it's impossible to ever reach the
   137  * 			return-with-no-value. UGH!
   138  */
   139 #define ACCESS_CHECK_RD(address, bits) do {							\
   140 		bool fault = false;											\
   141 		/* MEM_STATUS st; */										\
   142 		switch (checkMemoryAccess(address, false)) {				\
   143 			case MEM_ALLOWED:										\
   144 				/* Access allowed */								\
   145 				break;												\
   146 			case MEM_PAGEFAULT:										\
   147 				/* Page fault */									\
   148 				state.genstat = 0xCBFF | (state.pie ? 0x0400 : 0);	\
   149 				fault = true;										\
   150 				break;												\
   151 			case MEM_UIE:											\
   152 				/* User access to memory above 4MB */				\
   153 				state.genstat = 0xDAFF | (state.pie ? 0x0400 : 0);	\
   154 				fault = true;										\
   155 				break;												\
   156 			case MEM_KERNEL:										\
   157 			case MEM_PAGE_NO_WE:									\
   158 				/* kernel access or page not write enabled */		\
   159 				/* TODO: which regs need setting? */				\
   160 				fault = true;										\
   161 				break;												\
   162 		}															\
   163 																	\
   164 		if (fault) {												\
   165 			if (bits >= 16)											\
   166 				state.bsr0 = 0x7F00;								\
   167 			else													\
   168 				state.bsr0 = (address & 1) ? 0x7D00 : 0x7E00;		\
   169 			state.bsr0 |= (address >> 16);							\
   170 			state.bsr1 = address & 0xffff;							\
   171 			printf("ERR: BusError RD\n");							\
   172 			m68k_pulse_bus_error();									\
   173 			return 0xFFFFFFFF;										\
   174 		}															\
   175 	} while (false)
   177 // Logging macros
   178 #define LOG_NOT_HANDLED_R(bits)																	\
   179 	do {																						\
   180 		if (!handled)																			\
   181 			printf("unhandled read%02d, addr=0x%08X\n", bits, address);							\
   182 	} while (0);
   184 #define LOG_NOT_HANDLED_W(bits)																	\
   185 	do {																						\
   186 		if (!handled)																			\
   187 			printf("unhandled write%02d, addr=0x%08X, data=0x%08X\n", bits, address, value);	\
   188 	} while (0);
   190 /**
   191  * @brief Read M68K memory, 32-bit
   192  */
   193 uint32_t m68k_read_memory_32(uint32_t address)
   194 {
   195 	uint32_t data = 0xFFFFFFFF;
   196 	bool handled = false;
   198 	// If ROMLMAP is set, force system to access ROM
   199 	if (!state.romlmap)
   200 		address |= 0x800000;
   202 	// Check access permissions
   203 	ACCESS_CHECK_RD(address, 32);
   205 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   206 		// ROM access
   207 		data = RD32(state.rom, address, ROM_SIZE - 1);
   208 		handled = true;
   209 	} else if (address <= (state.ram_size - 1)) {
   210 		// RAM access
   211 		data = RD32(state.ram, mapAddr(address, false), state.ram_size - 1);
   212 		handled = true;
   213 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   214 		// I/O register space, zone A
   215 		switch (address & 0x0F0000) {
   216 			case 0x000000:				// Map RAM access
   217 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD32 from MapRAM mirror, addr=0x%08X\n", address);
   218 				data = RD32(state.map, address, 0x7FF);
   219 				handled = true;
   220 				break;
   221 			case 0x010000:				// General Status Register
   222 				data = ((uint32_t)state.genstat << 16) + (uint32_t)state.genstat;
   223 				handled = true;
   224 				break;
   225 			case 0x020000:				// Video RAM
   226 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD32 from VideoRAM mirror, addr=0x%08X\n", address);
   227 				data = RD32(state.vram, address, 0x7FFF);
   228 				handled = true;
   229 				break;
   230 			case 0x030000:				// Bus Status Register 0
   231 				data = ((uint32_t)state.bsr0 << 16) + (uint32_t)state.bsr0;
   232 				handled = true;
   233 				break;
   234 			case 0x040000:				// Bus Status Register 1
   235 				data = ((uint32_t)state.bsr1 << 16) + (uint32_t)state.bsr1;
   236 				handled = true;
   237 				break;
   238 			case 0x050000:				// Phone status
   239 				break;
   240 			case 0x060000:				// DMA Count
   241 				// U/OERR- is always inactive (bit set)
   242 				data = (state.dma_count & 0x3fff) | 0x8000;
   243 				handled = true;
   244 				break;
   245 			case 0x070000:				// Line Printer Status Register
   246 				data = 0x00120012;	// no parity error, no line printer error, no irqs from FDD or HDD
   247 				data |= (state.fdc_ctx.irql) ? 0x00080008 : 0;	// FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this
   248 				break;
   249 			case 0x080000:				// Real Time Clock
   250 				break;
   251 			case 0x090000:				// Phone registers
   252 				switch (address & 0x0FF000) {
   253 					case 0x090000:		// Handset relay
   254 					case 0x098000:
   255 						break;
   256 					case 0x091000:		// Line select 2
   257 					case 0x099000:
   258 						break;
   259 					case 0x092000:		// Hook relay 1
   260 					case 0x09A000:
   261 						break;
   262 					case 0x093000:		// Hook relay 2
   263 					case 0x09B000:
   264 						break;
   265 					case 0x094000:		// Line 1 hold
   266 					case 0x09C000:
   267 						break;
   268 					case 0x095000:		// Line 2 hold
   269 					case 0x09D000:
   270 						break;
   271 					case 0x096000:		// Line 1 A-lead
   272 					case 0x09E000:
   273 						break;
   274 					case 0x097000:		// Line 2 A-lead
   275 					case 0x09F000:
   276 						break;
   277 				}
   278 				break;
   279 			case 0x0A0000:				// Miscellaneous Control Register -- write only!
   280 				handled = true;
   281 				break;
   282 			case 0x0B0000:				// TM/DIALWR
   283 				break;
   284 			case 0x0C0000:				// Clear Status Register -- write only!
   285 				handled = true;
   286 				break;
   287 			case 0x0D0000:				// DMA Address Register
   288 				break;
   289 			case 0x0E0000:				// Disk Control Register
   290 				break;
   291 			case 0x0F0000:				// Line Printer Data Register
   292 				break;
   293 		}
   294 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   295 		// I/O register space, zone B
   296 		switch (address & 0xF00000) {
   297 			case 0xC00000:				// Expansion slots
   298 			case 0xD00000:
   299 				switch (address & 0xFC0000) {
   300 					case 0xC00000:		// Expansion slot 0
   301 					case 0xC40000:		// Expansion slot 1
   302 					case 0xC80000:		// Expansion slot 2
   303 					case 0xCC0000:		// Expansion slot 3
   304 					case 0xD00000:		// Expansion slot 4
   305 					case 0xD40000:		// Expansion slot 5
   306 					case 0xD80000:		// Expansion slot 6
   307 					case 0xDC0000:		// Expansion slot 7
   308 						fprintf(stderr, "NOTE: RD32 from expansion card space, addr=0x%08X\n", address);
   309 						break;
   310 				}
   311 				break;
   312 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   313 			case 0xF00000:
   314 				switch (address & 0x070000) {
   315 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   316 						break;
   317 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   318 						data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
   319 						printf("WD279X: rd32 %02X ==> %02X\n", (address >> 1) & 3, data);
   320 						handled = true;
   321 						break;
   322 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   323 						break;
   324 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   325 						break;
   326 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   327 						switch (address & 0x077000) {
   328 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   329 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   330 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   331 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   332 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   333 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   334 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   335 								// All write-only registers... TODO: bus error?
   336 								handled = true;
   337 								break;
   338 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video [FIXME: not in TRM]
   339 								break;
   340 						}
   341 						break;
   342 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   343 						break;
   344 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   345 						switch (address & 0x07F000) {
   346 							default:
   347 								break;
   348 						}
   349 						break;
   350 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   351 						break;
   352 				}
   353 		}
   354 	}
   356 	LOG_NOT_HANDLED_R(32);
   357 	return data;
   358 }
   360 /**
   361  * @brief Read M68K memory, 16-bit
   362  */
   363 uint32_t m68k_read_memory_16(uint32_t address)
   364 {
   365 	uint16_t data = 0xFFFF;
   366 	bool handled = false;
   368 	// If ROMLMAP is set, force system to access ROM
   369 	if (!state.romlmap)
   370 		address |= 0x800000;
   372 	// Check access permissions
   373 	ACCESS_CHECK_RD(address, 16);
   375 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   376 		// ROM access
   377 		data = RD16(state.rom, address, ROM_SIZE - 1);
   378 		handled = true;
   379 	} else if (address <= (state.ram_size - 1)) {
   380 		// RAM access
   381 		data = RD16(state.ram, mapAddr(address, false), state.ram_size - 1);
   382 		handled = true;
   383 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   384 		// I/O register space, zone A
   385 		switch (address & 0x0F0000) {
   386 			case 0x000000:				// Map RAM access
   387 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD16 from MapRAM mirror, addr=0x%08X\n", address);
   388 				data = RD16(state.map, address, 0x7FF);
   389 				handled = true;
   390 				break;
   391 			case 0x010000:				// General Status Register
   392 				data = state.genstat;
   393 				handled = true;
   394 				break;
   395 			case 0x020000:				// Video RAM
   396 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD16 from VideoRAM mirror, addr=0x%08X\n", address);
   397 				data = RD16(state.vram, address, 0x7FFF);
   398 				handled = true;
   399 				break;
   400 			case 0x030000:				// Bus Status Register 0
   401 				data = state.bsr0;
   402 				handled = true;
   403 				break;
   404 			case 0x040000:				// Bus Status Register 1
   405 				data = state.bsr1;
   406 				handled = true;
   407 				break;
   408 			case 0x050000:				// Phone status
   409 				break;
   410 			case 0x060000:				// DMA Count
   411 				// U/OERR- is always inactive (bit set)
   412 				data = (state.dma_count & 0x3fff) | 0x8000;
   413 				handled = true;
   414 				break;
   415 			case 0x070000:				// Line Printer Status Register
   416 				data = 0x0012;	// no parity error, no line printer error, no irqs from FDD or HDD
   417 				data |= (state.fdc_ctx.irql) ? 0x0008 : 0;	// FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this
   418 				break;
   419 			case 0x080000:				// Real Time Clock
   420 				break;
   421 			case 0x090000:				// Phone registers
   422 				switch (address & 0x0FF000) {
   423 					case 0x090000:		// Handset relay
   424 					case 0x098000:
   425 						break;
   426 					case 0x091000:		// Line select 2
   427 					case 0x099000:
   428 						break;
   429 					case 0x092000:		// Hook relay 1
   430 					case 0x09A000:
   431 						break;
   432 					case 0x093000:		// Hook relay 2
   433 					case 0x09B000:
   434 						break;
   435 					case 0x094000:		// Line 1 hold
   436 					case 0x09C000:
   437 						break;
   438 					case 0x095000:		// Line 2 hold
   439 					case 0x09D000:
   440 						break;
   441 					case 0x096000:		// Line 1 A-lead
   442 					case 0x09E000:
   443 						break;
   444 					case 0x097000:		// Line 2 A-lead
   445 					case 0x09F000:
   446 						break;
   447 				}
   448 				break;
   449 			case 0x0A0000:				// Miscellaneous Control Register -- write only!
   450 				handled = true;
   451 				break;
   452 			case 0x0B0000:				// TM/DIALWR
   453 				break;
   454 			case 0x0C0000:				// Clear Status Register -- write only!
   455 				handled = true;
   456 				break;
   457 			case 0x0D0000:				// DMA Address Register
   458 				break;
   459 			case 0x0E0000:				// Disk Control Register
   460 				break;
   461 			case 0x0F0000:				// Line Printer Data Register
   462 				break;
   463 		}
   464 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   465 		// I/O register space, zone B
   466 		switch (address & 0xF00000) {
   467 			case 0xC00000:				// Expansion slots
   468 			case 0xD00000:
   469 				switch (address & 0xFC0000) {
   470 					case 0xC00000:		// Expansion slot 0
   471 					case 0xC40000:		// Expansion slot 1
   472 					case 0xC80000:		// Expansion slot 2
   473 					case 0xCC0000:		// Expansion slot 3
   474 					case 0xD00000:		// Expansion slot 4
   475 					case 0xD40000:		// Expansion slot 5
   476 					case 0xD80000:		// Expansion slot 6
   477 					case 0xDC0000:		// Expansion slot 7
   478 						fprintf(stderr, "NOTE: RD16 from expansion card space, addr=0x%08X\n", address);
   479 						break;
   480 				}
   481 				break;
   482 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   483 			case 0xF00000:
   484 				switch (address & 0x070000) {
   485 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   486 						break;
   487 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   488 						data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
   489 						printf("WD279X: rd16 %02X ==> %02X\n", (address >> 1) & 3, data);
   490 						handled = true;
   491 						break;
   492 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   493 						break;
   494 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   495 						break;
   496 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   497 						switch (address & 0x077000) {
   498 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   499 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   500 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   501 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   502 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   503 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   504 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   505 								// All write-only registers... TODO: bus error?
   506 								handled = true;
   507 								break;
   508 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   509 								break;
   510 						}
   511 						break;
   512 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   513 						break;
   514 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   515 						switch (address & 0x07F000) {
   516 							default:
   517 								break;
   518 						}
   519 						break;
   520 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   521 						break;
   522 				}
   523 		}
   524 	}
   526 	LOG_NOT_HANDLED_R(16);
   527 	return data;
   528 }
   530 /**
   531  * @brief Read M68K memory, 8-bit
   532  */
   533 uint32_t m68k_read_memory_8(uint32_t address)
   534 {
   535 	uint8_t data = 0xFF;
   536 	bool handled = false;
   538 	// If ROMLMAP is set, force system to access ROM
   539 	if (!state.romlmap)
   540 		address |= 0x800000;
   542 	// Check access permissions
   543 	ACCESS_CHECK_RD(address, 8);
   545 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   546 		// ROM access
   547 		data = RD8(state.rom, address, ROM_SIZE - 1);
   548 		handled = true;
   549 	} else if (address <= (state.ram_size - 1)) {
   550 		// RAM access
   551 		data = RD8(state.ram, mapAddr(address, false), state.ram_size - 1);
   552 		handled = true;
   553 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   554 		// I/O register space, zone A
   555 		switch (address & 0x0F0000) {
   556 			case 0x000000:				// Map RAM access
   557 				if (address > 0x4007FF) fprintf(stderr, "NOTE: RD8 from MapRAM mirror, addr=0x%08X\n", address);
   558 				data = RD8(state.map, address, 0x7FF);
   559 				handled = true;
   560 				break;
   561 			case 0x010000:				// General Status Register
   562 				if ((address & 1) == 0)
   563 					data = (state.genstat >> 8) & 0xff;
   564 				else
   565 					data = (state.genstat)      & 0xff;
   566 				handled = true;
   567 				break;
   568 			case 0x020000:				// Video RAM
   569 				if (address > 0x427FFF) fprintf(stderr, "NOTE: RD8 from VideoRAM mirror, addr=0x%08X\n", address);
   570 				data = RD8(state.vram, address, 0x7FFF);
   571 				handled = true;
   572 				break;
   573 			case 0x030000:				// Bus Status Register 0
   574 				if ((address & 1) == 0)
   575 					data = (state.bsr0 >> 8) & 0xff;
   576 				else
   577 					data = (state.bsr0)      & 0xff;
   578 				handled = true;
   579 				break;
   580 			case 0x040000:				// Bus Status Register 1
   581 				if ((address & 1) == 0)
   582 					data = (state.bsr1 >> 8) & 0xff;
   583 				else
   584 					data = (state.bsr1)      & 0xff;
   585 				handled = true;
   586 				break;
   587 			case 0x050000:				// Phone status
   588 				break;
   589 			case 0x060000:				// DMA Count
   590 				// TODO: how to handle this in 8bit mode?
   591 				break;
   592 			case 0x070000:				// Line Printer Status Register
   593 				printf("\tLPSR RD8 fdc irql=%d, irqe=%d\n", state.fdc_ctx.irql, state.fdc_ctx.irqe);
   594 				if (address & 1) {
   595 					data = 0x12;	// no parity error, no line printer error, no irqs from FDD or HDD
   596 					data |= (state.fdc_ctx.irql) ? 0x08 : 0;	// FIXME! HACKHACKHACK! shouldn't peek inside FDC structs like this
   597 				} else {
   598 					data = 0;
   599 				}
   600 				break;
   601 			case 0x080000:				// Real Time Clock
   602 				break;
   603 			case 0x090000:				// Phone registers
   604 				switch (address & 0x0FF000) {
   605 					case 0x090000:		// Handset relay
   606 					case 0x098000:
   607 						break;
   608 					case 0x091000:		// Line select 2
   609 					case 0x099000:
   610 						break;
   611 					case 0x092000:		// Hook relay 1
   612 					case 0x09A000:
   613 						break;
   614 					case 0x093000:		// Hook relay 2
   615 					case 0x09B000:
   616 						break;
   617 					case 0x094000:		// Line 1 hold
   618 					case 0x09C000:
   619 						break;
   620 					case 0x095000:		// Line 2 hold
   621 					case 0x09D000:
   622 						break;
   623 					case 0x096000:		// Line 1 A-lead
   624 					case 0x09E000:
   625 						break;
   626 					case 0x097000:		// Line 2 A-lead
   627 					case 0x09F000:
   628 						break;
   629 				}
   630 				break;
   631 			case 0x0A0000:				// Miscellaneous Control Register -- write only!
   632 				handled = true;
   633 				break;
   634 			case 0x0B0000:				// TM/DIALWR
   635 				break;
   636 			case 0x0C0000:				// Clear Status Register -- write only!
   637 				handled = true;
   638 				break;
   639 			case 0x0D0000:				// DMA Address Register
   640 				break;
   641 			case 0x0E0000:				// Disk Control Register
   642 				break;
   643 			case 0x0F0000:				// Line Printer Data Register
   644 				break;
   645 		}
   646 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   647 		// I/O register space, zone B
   648 		switch (address & 0xF00000) {
   649 			case 0xC00000:				// Expansion slots
   650 			case 0xD00000:
   651 				switch (address & 0xFC0000) {
   652 					case 0xC00000:		// Expansion slot 0
   653 					case 0xC40000:		// Expansion slot 1
   654 					case 0xC80000:		// Expansion slot 2
   655 					case 0xCC0000:		// Expansion slot 3
   656 					case 0xD00000:		// Expansion slot 4
   657 					case 0xD40000:		// Expansion slot 5
   658 					case 0xD80000:		// Expansion slot 6
   659 					case 0xDC0000:		// Expansion slot 7
   660 						fprintf(stderr, "NOTE: RD8 from expansion card space, addr=0x%08X\n", address);
   661 						break;
   662 				}
   663 				break;
   664 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   665 			case 0xF00000:
   666 				switch (address & 0x070000) {
   667 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   668 						break;
   669 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   670 						data = wd2797_read_reg(&state.fdc_ctx, (address >> 1) & 3);
   671 						printf("WD279X: rd8 %02X ==> %02X\n", (address >> 1) & 3, data);
   672 						handled = true;
   673 						break;
   674 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   675 						break;
   676 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   677 						break;
   678 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   679 						switch (address & 0x077000) {
   680 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   681 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   682 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   683 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   684 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   685 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   686 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   687 								// All write-only registers... TODO: bus error?
   688 								handled = true;
   689 								break;
   690 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   691 								break;
   692 						}
   693 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   694 						break;
   695 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   696 						switch (address & 0x07F000) {
   697 							default:
   698 								break;
   699 						}
   700 						break;
   701 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   702 						break;
   703 				}
   704 		}
   705 	}
   707 	LOG_NOT_HANDLED_R(8);
   709 	return data;
   710 }
   712 /**
   713  * @brief Write M68K memory, 32-bit
   714  */
   715 void m68k_write_memory_32(uint32_t address, uint32_t value)
   716 {
   717 	bool handled = false;
   719 	// If ROMLMAP is set, force system to access ROM
   720 	if (!state.romlmap)
   721 		address |= 0x800000;
   723 	// Check access permissions
   724 	ACCESS_CHECK_WR(address, 32);
   726 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   727 		// ROM access
   728 		handled = true;
   729 	} else if (address <= (state.ram_size - 1)) {
   730 		// RAM access
   731 		WR32(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   732 		handled = true;
   733 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   734 		// I/O register space, zone A
   735 		switch (address & 0x0F0000) {
   736 			case 0x000000:				// Map RAM access
   737 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR32 to MapRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   738 				WR32(state.map, address, 0x7FF, value);
   739 				handled = true;
   740 				break;
   741 			case 0x010000:				// General Status Register
   742 				state.genstat = (value & 0xffff);
   743 				handled = true;
   744 				break;
   745 			case 0x020000:				// Video RAM
   746 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR32 to VideoRAM mirror, addr=0x%08X, data=0x%08X\n", address, value);
   747 				WR32(state.vram, address, 0x7FFF, value);
   748 				handled = true;
   749 				break;
   750 			case 0x030000:				// Bus Status Register 0
   751 				break;
   752 			case 0x040000:				// Bus Status Register 1
   753 				break;
   754 			case 0x050000:				// Phone status
   755 				break;
   756 			case 0x060000:				// DMA Count
   757 				printf("WR32 dmacount %08X\n", value);
   758 				state.dma_count = (value & 0x3FFF);
   759 				state.idmarw = ((value & 0x4000) == 0x4000);
   760 				state.dmaen = ((value & 0x8000) == 0x8000);
   761 				state.dmaenb = state.dmaen;
   762 				printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen);
   763 				handled = true;
   764 				break;
   765 			case 0x070000:				// Line Printer Status Register
   766 				break;
   767 			case 0x080000:				// Real Time Clock
   768 				break;
   769 			case 0x090000:				// Phone registers
   770 				switch (address & 0x0FF000) {
   771 					case 0x090000:		// Handset relay
   772 					case 0x098000:
   773 						break;
   774 					case 0x091000:		// Line select 2
   775 					case 0x099000:
   776 						break;
   777 					case 0x092000:		// Hook relay 1
   778 					case 0x09A000:
   779 						break;
   780 					case 0x093000:		// Hook relay 2
   781 					case 0x09B000:
   782 						break;
   783 					case 0x094000:		// Line 1 hold
   784 					case 0x09C000:
   785 						break;
   786 					case 0x095000:		// Line 2 hold
   787 					case 0x09D000:
   788 						break;
   789 					case 0x096000:		// Line 1 A-lead
   790 					case 0x09E000:
   791 						break;
   792 					case 0x097000:		// Line 2 A-lead
   793 					case 0x09F000:
   794 						break;
   795 				}
   796 				break;
   797 			case 0x0A0000:				// Miscellaneous Control Register
   798 				// TODO: handle the ctrl bits properly
   799 				// TODO: &0x8000 --> dismiss 60hz intr
   800 				state.dma_reading = (value & 0x4000);
   801 				state.leds = (~value & 0xF00) >> 8;
   802 				printf("LEDs: %s %s %s %s\n",
   803 						(state.leds & 8) ? "R" : "-",
   804 						(state.leds & 4) ? "G" : "-",
   805 						(state.leds & 2) ? "Y" : "-",
   806 						(state.leds & 1) ? "R" : "-");
   807 				handled = true;
   808 				break;
   809 			case 0x0B0000:				// TM/DIALWR
   810 				break;
   811 			case 0x0C0000:				// Clear Status Register
   812 				state.genstat = 0xFFFF;
   813 				state.bsr0 = 0xFFFF;
   814 				state.bsr1 = 0xFFFF;
   815 				handled = true;
   816 				break;
   817 			case 0x0D0000:				// DMA Address Register
   818 				if (address & 0x004000) {
   819 					// A14 high -- set most significant bits
   820 					state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7);
   821 				} else {
   822 					// A14 low -- set least significant bits
   823 					state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff);
   824 				}
   825 				printf("WR DMA_ADDR, now %08X\n", state.dma_address);
   826 				handled = true;
   827 				break;
   828 			case 0x0E0000:				// Disk Control Register
   829 				// B7 = FDD controller reset
   830 				if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
   831 				// B6 = drive 0 select -- TODO
   832 				// B5 = motor enable -- TODO
   833 				// B4 = HDD controller reset -- TODO
   834 				// B3 = HDD0 select -- TODO
   835 				// B2,1,0 = HDD0 head select
   836 				handled = true;
   837 				break;
   838 			case 0x0F0000:				// Line Printer Data Register
   839 				break;
   840 		}
   841 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
   842 		// I/O register space, zone B
   843 		switch (address & 0xF00000) {
   844 			case 0xC00000:				// Expansion slots
   845 			case 0xD00000:
   846 				switch (address & 0xFC0000) {
   847 					case 0xC00000:		// Expansion slot 0
   848 					case 0xC40000:		// Expansion slot 1
   849 					case 0xC80000:		// Expansion slot 2
   850 					case 0xCC0000:		// Expansion slot 3
   851 					case 0xD00000:		// Expansion slot 4
   852 					case 0xD40000:		// Expansion slot 5
   853 					case 0xD80000:		// Expansion slot 6
   854 					case 0xDC0000:		// Expansion slot 7
   855 						fprintf(stderr, "NOTE: WR32 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
   856 						handled = true;
   857 						break;
   858 				}
   859 				break;
   860 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
   861 			case 0xF00000:
   862 				switch (address & 0x070000) {
   863 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
   864 						break;
   865 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
   866 						printf("WD279X: wr32 %02X ==> %02X\n", (address >> 1) & 3, value);
   867 						wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value);
   868 						handled = true;
   869 						break;
   870 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
   871 						break;
   872 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
   873 						break;
   874 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
   875 						switch (address & 0x077000) {
   876 							case 0x040000:		// [ef][4c][08]xxx ==> EE
   877 								break;
   878 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
   879 								state.pie = ((value & 0x8000) == 0x8000);
   880 								handled = true;
   881 								break;
   882 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
   883 								break;
   884 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
   885 								state.romlmap = ((value & 0x8000) == 0x8000);
   886 								handled = true;
   887 								break;
   888 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
   889 								break;
   890 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
   891 								break;
   892 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
   893 								break;
   894 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
   895 								break;
   896 						}
   897 					case 0x050000:		// [ef][5d]xxxx ==> 8274
   898 						break;
   899 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
   900 						switch (address & 0x07F000) {
   901 							default:
   902 								break;
   903 						}
   904 						break;
   905 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
   906 						break;
   907 				}
   908 		}
   909 	}
   911 	LOG_NOT_HANDLED_W(32);
   912 }
   914 /**
   915  * @brief Write M68K memory, 16-bit
   916  */
   917 void m68k_write_memory_16(uint32_t address, uint32_t value)
   918 {
   919 	bool handled = false;
   921 	// If ROMLMAP is set, force system to access ROM
   922 	if (!state.romlmap)
   923 		address |= 0x800000;
   925 	// Check access permissions
   926 	ACCESS_CHECK_WR(address, 16);
   928 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   929 		// ROM access
   930 		handled = true;
   931 	} else if (address <= (state.ram_size - 1)) {
   932 		// RAM access
   933 		WR16(state.ram, mapAddr(address, false), state.ram_size - 1, value);
   934 		handled = true;
   935 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   936 		// I/O register space, zone A
   937 		switch (address & 0x0F0000) {
   938 			case 0x000000:				// Map RAM access
   939 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR16 to MapRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   940 				WR16(state.map, address, 0x7FF, value);
   941 				handled = true;
   942 				break;
   943 			case 0x010000:				// General Status Register (read only)
   944 				handled = true;
   945 				break;
   946 			case 0x020000:				// Video RAM
   947 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR16 to VideoRAM mirror, addr=0x%08X, data=0x%04X\n", address, value);
   948 				WR16(state.vram, address, 0x7FFF, value);
   949 				handled = true;
   950 				break;
   951 			case 0x030000:				// Bus Status Register 0 (read only)
   952 				handled = true;
   953 				break;
   954 			case 0x040000:				// Bus Status Register 1 (read only)
   955 				handled = true;
   956 				break;
   957 			case 0x050000:				// Phone status
   958 				break;
   959 			case 0x060000:				// DMA Count
   960 				printf("WR16 dmacount %08X\n", value);
   961 				state.dma_count = (value & 0x3FFF);
   962 				state.idmarw = ((value & 0x4000) == 0x4000);
   963 				state.dmaen = ((value & 0x8000) == 0x8000);
   964 				state.dmaenb = state.dmaen;
   965 				printf("\tcount %04X, idmarw %d, dmaen %d\n", state.dma_count, state.idmarw, state.dmaen);
   966 				handled = true;
   967 				break;
   968 			case 0x070000:				// Line Printer Status Register
   969 				break;
   970 			case 0x080000:				// Real Time Clock
   971 				break;
   972 			case 0x090000:				// Phone registers
   973 				switch (address & 0x0FF000) {
   974 					case 0x090000:		// Handset relay
   975 					case 0x098000:
   976 						break;
   977 					case 0x091000:		// Line select 2
   978 					case 0x099000:
   979 						break;
   980 					case 0x092000:		// Hook relay 1
   981 					case 0x09A000:
   982 						break;
   983 					case 0x093000:		// Hook relay 2
   984 					case 0x09B000:
   985 						break;
   986 					case 0x094000:		// Line 1 hold
   987 					case 0x09C000:
   988 						break;
   989 					case 0x095000:		// Line 2 hold
   990 					case 0x09D000:
   991 						break;
   992 					case 0x096000:		// Line 1 A-lead
   993 					case 0x09E000:
   994 						break;
   995 					case 0x097000:		// Line 2 A-lead
   996 					case 0x09F000:
   997 						break;
   998 				}
   999 				break;
  1000 			case 0x0A0000:				// Miscellaneous Control Register
  1001 				// TODO: handle the ctrl bits properly
  1002 				// TODO: &0x8000 --> dismiss 60hz intr
  1003 				state.dma_reading = (value & 0x4000);
  1004 				state.leds = (~value & 0xF00) >> 8;
  1005 				printf("LEDs: %s %s %s %s\n",
  1006 						(state.leds & 8) ? "R" : "-",
  1007 						(state.leds & 4) ? "G" : "-",
  1008 						(state.leds & 2) ? "Y" : "-",
  1009 						(state.leds & 1) ? "R" : "-");
  1010 				handled = true;
  1011 				break;
  1012 			case 0x0B0000:				// TM/DIALWR
  1013 				break;
  1014 			case 0x0C0000:				// Clear Status Register
  1015 				state.genstat = 0xFFFF;
  1016 				state.bsr0 = 0xFFFF;
  1017 				state.bsr1 = 0xFFFF;
  1018 				handled = true;
  1019 				break;
  1020 			case 0x0D0000:				// DMA Address Register
  1021 				if (address & 0x004000) {
  1022 					// A14 high -- set most significant bits
  1023 					state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7);
  1024 				} else {
  1025 					// A14 low -- set least significant bits
  1026 					state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff);
  1028 				printf("WR DMA_ADDR, now %08X\n", state.dma_address);
  1029 				handled = true;
  1030 				break;
  1031 			case 0x0E0000:				// Disk Control Register
  1032 				// B7 = FDD controller reset
  1033 				if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
  1034 				// B6 = drive 0 select -- TODO
  1035 				// B5 = motor enable -- TODO
  1036 				// B4 = HDD controller reset -- TODO
  1037 				// B3 = HDD0 select -- TODO
  1038 				// B2,1,0 = HDD0 head select
  1039 				handled = true;
  1040 				break;
  1041 			case 0x0F0000:				// Line Printer Data Register
  1042 				break;
  1044 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
  1045 		// I/O register space, zone B
  1046 		switch (address & 0xF00000) {
  1047 			case 0xC00000:				// Expansion slots
  1048 			case 0xD00000:
  1049 				switch (address & 0xFC0000) {
  1050 					case 0xC00000:		// Expansion slot 0
  1051 					case 0xC40000:		// Expansion slot 1
  1052 					case 0xC80000:		// Expansion slot 2
  1053 					case 0xCC0000:		// Expansion slot 3
  1054 					case 0xD00000:		// Expansion slot 4
  1055 					case 0xD40000:		// Expansion slot 5
  1056 					case 0xD80000:		// Expansion slot 6
  1057 					case 0xDC0000:		// Expansion slot 7
  1058 						fprintf(stderr, "NOTE: WR16 to expansion card space, addr=0x%08X, data=0x%04X\n", address, value);
  1059 						break;
  1061 				break;
  1062 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
  1063 			case 0xF00000:
  1064 				switch (address & 0x070000) {
  1065 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
  1066 						break;
  1067 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
  1068 						printf("WD279X: wr16 %02X ==> %02X\n", (address >> 1) & 3, value);
  1069 						wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value);
  1070 						handled = true;
  1071 						break;
  1072 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
  1073 						break;
  1074 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
  1075 						break;
  1076 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
  1077 						switch (address & 0x077000) {
  1078 							case 0x040000:		// [ef][4c][08]xxx ==> EE
  1079 								break;
  1080 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
  1081 								state.pie = ((value & 0x8000) == 0x8000);
  1082 								handled = true;
  1083 								break;
  1084 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
  1085 								break;
  1086 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
  1087 								state.romlmap = ((value & 0x8000) == 0x8000);
  1088 								handled = true;
  1089 								break;
  1090 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
  1091 								break;
  1092 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
  1093 								break;
  1094 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
  1095 								break;
  1096 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
  1097 								break;
  1099 					case 0x050000:		// [ef][5d]xxxx ==> 8274
  1100 						break;
  1101 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
  1102 						switch (address & 0x07F000) {
  1103 							default:
  1104 								break;
  1106 						break;
  1107 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
  1108 						break;
  1113 	LOG_NOT_HANDLED_W(16);
  1116 /**
  1117  * @brief Write M68K memory, 8-bit
  1118  */
  1119 void m68k_write_memory_8(uint32_t address, uint32_t value)
  1121 	bool handled = false;
  1123 	// If ROMLMAP is set, force system to access ROM
  1124 	if (!state.romlmap)
  1125 		address |= 0x800000;
  1127 	// Check access permissions
  1128 	ACCESS_CHECK_WR(address, 8);
  1130 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
  1131 		// ROM access (read only!)
  1132 		handled = true;
  1133 	} else if (address <= (state.ram_size - 1)) {
  1134 		// RAM access
  1135 		WR8(state.ram, mapAddr(address, false), state.ram_size - 1, value);
  1136 		handled = true;
  1137 	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
  1138 		// I/O register space, zone A
  1139 		switch (address & 0x0F0000) {
  1140 			case 0x000000:				// Map RAM access
  1141 				if (address > 0x4007FF) fprintf(stderr, "NOTE: WR8 to MapRAM mirror, addr=%08X, data=%02X\n", address, value);
  1142 				WR8(state.map, address, 0x7FF, value);
  1143 				handled = true;
  1144 				break;
  1145 			case 0x010000:				// General Status Register
  1146 				handled = true;
  1147 				break;
  1148 			case 0x020000:				// Video RAM
  1149 				if (address > 0x427FFF) fprintf(stderr, "NOTE: WR8 to VideoRAM mirror, addr=%08X, data=0x%02X\n", address, value);
  1150 				WR8(state.vram, address, 0x7FFF, value);
  1151 				handled = true;
  1152 				break;
  1153 			case 0x030000:				// Bus Status Register 0
  1154 				handled = true;
  1155 				break;
  1156 			case 0x040000:				// Bus Status Register 1
  1157 				handled = true;
  1158 				break;
  1159 			case 0x050000:				// Phone status
  1160 				break;
  1161 			case 0x060000:				// DMA Count
  1162 				// TODO: how to handle this in 8bit mode?
  1163 				break;
  1164 			case 0x070000:				// Line Printer Status Register
  1165 				break;
  1166 			case 0x080000:				// Real Time Clock
  1167 				break;
  1168 			case 0x090000:				// Phone registers
  1169 				switch (address & 0x0FF000) {
  1170 					case 0x090000:		// Handset relay
  1171 					case 0x098000:
  1172 						break;
  1173 					case 0x091000:		// Line select 2
  1174 					case 0x099000:
  1175 						break;
  1176 					case 0x092000:		// Hook relay 1
  1177 					case 0x09A000:
  1178 						break;
  1179 					case 0x093000:		// Hook relay 2
  1180 					case 0x09B000:
  1181 						break;
  1182 					case 0x094000:		// Line 1 hold
  1183 					case 0x09C000:
  1184 						break;
  1185 					case 0x095000:		// Line 2 hold
  1186 					case 0x09D000:
  1187 						break;
  1188 					case 0x096000:		// Line 1 A-lead
  1189 					case 0x09E000:
  1190 						break;
  1191 					case 0x097000:		// Line 2 A-lead
  1192 					case 0x09F000:
  1193 						break;
  1195 				break;
  1196 			case 0x0A0000:				// Miscellaneous Control Register
  1197 				// TODO: how to handle this in 8bit mode?
  1198 /*
  1199 				// TODO: handle the ctrl bits properly
  1200 				if ((address & 1) == 0) {
  1201 					// low byte
  1202 				} else {
  1203 					// hight byte
  1204 					// TODO: &0x8000 --> dismiss 60hz intr
  1205 					state.dma_reading = (value & 0x40);
  1206 					state.leds = (~value & 0xF);
  1208 				printf("LEDs: %s %s %s %s\n",
  1209 						(state.leds & 8) ? "R" : "-",
  1210 						(state.leds & 4) ? "G" : "-",
  1211 						(state.leds & 2) ? "Y" : "-",
  1212 						(state.leds & 1) ? "R" : "-");
  1213 				handled = true;
  1214 */
  1215 				break;
  1216 			case 0x0B0000:				// TM/DIALWR
  1217 				break;
  1218 			case 0x0C0000:				// Clear Status Register
  1219 				state.genstat = 0xFFFF;
  1220 				state.bsr0 = 0xFFFF;
  1221 				state.bsr1 = 0xFFFF;
  1222 				handled = true;
  1223 				break;
  1224 			case 0x0D0000:				// DMA Address Register
  1225 				if (address & 0x004000) {
  1226 					// A14 high -- set most significant bits
  1227 					state.dma_address = (state.dma_address & 0xff) | ((address & 0x3fff) << 7);
  1228 				} else {
  1229 					// A14 low -- set least significant bits
  1230 					state.dma_address = (state.dma_address & 0x3fff00) | (address & 0xff);
  1232 				printf("WR DMA_ADDR, now %08X\n", state.dma_address);
  1233 				handled = true;
  1234 				break;
  1235 			case 0x0E0000:				// Disk Control Register
  1236 				// B7 = FDD controller reset
  1237 				if ((value & 0x80) == 0) wd2797_reset(&state.fdc_ctx);
  1238 				// B6 = drive 0 select -- TODO
  1239 				// B5 = motor enable -- TODO
  1240 				// B4 = HDD controller reset -- TODO
  1241 				// B3 = HDD0 select -- TODO
  1242 				// B2,1,0 = HDD0 head select
  1243 				handled = true;
  1244 				break;
  1245 			case 0x0F0000:				// Line Printer Data Register
  1246 				break;
  1248 	} else if ((address >= 0xC00000) && (address <= 0xFFFFFF)) {
  1249 		// I/O register space, zone B
  1250 		switch (address & 0xF00000) {
  1251 			case 0xC00000:				// Expansion slots
  1252 			case 0xD00000:
  1253 				switch (address & 0xFC0000) {
  1254 					case 0xC00000:		// Expansion slot 0
  1255 					case 0xC40000:		// Expansion slot 1
  1256 					case 0xC80000:		// Expansion slot 2
  1257 					case 0xCC0000:		// Expansion slot 3
  1258 					case 0xD00000:		// Expansion slot 4
  1259 					case 0xD40000:		// Expansion slot 5
  1260 					case 0xD80000:		// Expansion slot 6
  1261 					case 0xDC0000:		// Expansion slot 7
  1262 						fprintf(stderr, "NOTE: WR8 to expansion card space, addr=0x%08X, data=0x%08X\n", address, value);
  1263 						break;
  1265 				break;
  1266 			case 0xE00000:				// HDC, FDC, MCR2 and RTC data bits
  1267 			case 0xF00000:
  1268 				switch (address & 0x070000) {
  1269 					case 0x000000:		// [ef][08]xxxx ==> WD1010 hard disc controller
  1270 						break;
  1271 					case 0x010000:		// [ef][19]xxxx ==> WD2797 floppy disc controller
  1272 						printf("WD279X: wr8 %02X ==> %02X\n", (address >> 1) & 3, value);
  1273 						wd2797_write_reg(&state.fdc_ctx, (address >> 1) & 3, value);
  1274 						handled = true;
  1275 						break;
  1276 					case 0x020000:		// [ef][2a]xxxx ==> Miscellaneous Control Register 2
  1277 						break;
  1278 					case 0x030000:		// [ef][3b]xxxx ==> Real Time Clock data bits
  1279 						break;
  1280 					case 0x040000:		// [ef][4c]xxxx ==> General Control Register
  1281 						switch (address & 0x077000) {
  1282 							case 0x040000:		// [ef][4c][08]xxx ==> EE
  1283 								break;
  1284 							case 0x041000:		// [ef][4c][19]xxx ==> PIE
  1285 								if ((address & 1) == 0)
  1286 									state.pie = ((value & 0x80) == 0x80);
  1287 								handled = true;
  1288 								break;
  1289 							case 0x042000:		// [ef][4c][2A]xxx ==> BP
  1290 								break;
  1291 							case 0x043000:		// [ef][4c][3B]xxx ==> ROMLMAP
  1292 								if ((address & 1) == 0)
  1293 									state.romlmap = ((value & 0x80) == 0x80);
  1294 								handled = true;
  1295 								break;
  1296 							case 0x044000:		// [ef][4c][4C]xxx ==> L1 MODEM
  1297 								break;
  1298 							case 0x045000:		// [ef][4c][5D]xxx ==> L2 MODEM
  1299 								break;
  1300 							case 0x046000:		// [ef][4c][6E]xxx ==> D/N CONNECT
  1301 								break;
  1302 							case 0x047000:		// [ef][4c][7F]xxx ==> Whole screen reverse video
  1303 								break;
  1305 					case 0x050000:		// [ef][5d]xxxx ==> 8274
  1306 						break;
  1307 					case 0x060000:		// [ef][6e]xxxx ==> Control regs
  1308 						switch (address & 0x07F000) {
  1309 							default:
  1310 								break;
  1312 						break;
  1313 					case 0x070000:		// [ef][7f]xxxx ==> 6850 Keyboard Controller
  1314 						break;
  1315 					default:
  1316 						fprintf(stderr, "NOTE: WR8 to undefined E/F-block space, addr=0x%08X, data=0x%08X\n", address, value);
  1317 						break;
  1322 	LOG_NOT_HANDLED_W(8);
  1326 // for the disassembler
  1327 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
  1328 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
  1329 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }