changeset 1149:6b0da6021544

Don't lock up CPU if performing a read with writes configured when in PBC mode. Allow access to VDP debug commands from Z80 debugger in PBC mode. Handle Mode 4 in VDP debug print functions
author Michael Pavone <pavone@retrodev.com>
date Wed, 04 Jan 2017 20:43:22 -0800
parents 80ef49539550
children 322d28e6f13c
files backend.h debug.c romdb.h sms.c sms.h system.h vdp.c vdp.h
diffstat 8 files changed, 149 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/backend.h	Tue Jan 03 23:03:30 2017 -0800
+++ b/backend.h	Wed Jan 04 20:43:22 2017 -0800
@@ -76,6 +76,8 @@
 	write_8_fun  write_8;
 } memmap_chunk;
 
+#include "system.h"
+
 typedef struct {
 	uint32_t flags;
 	native_map_slot    *native_code_map;
@@ -90,6 +92,7 @@
 	code_ptr           handle_code_write;
 	code_ptr           handle_align_error_write;
 	code_ptr           handle_align_error_read;
+	system_str_fun_r8  debug_cmd_handler;
 	uint32_t           memmap_chunks;
 	uint32_t           address_mask;
 	uint32_t           max_address;
--- a/debug.c	Tue Jan 03 23:03:30 2017 -0800
+++ b/debug.c	Wed Jan 04 20:43:22 2017 -0800
@@ -523,7 +523,12 @@
 				break;
 			}
 			default:
-				fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
+				if (
+					!context->options->gen.debug_cmd_handler
+					|| !context->options->gen.debug_cmd_handler(&system->header, input_buf)
+				) {
+					fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
+				}
 				break;
 		}
 	}
--- a/romdb.h	Tue Jan 03 23:03:30 2017 -0800
+++ b/romdb.h	Wed Jan 04 20:43:22 2017 -0800
@@ -13,7 +13,6 @@
 #define SAVE_NONE     0xFF
 
 #include "tern.h"
-#include "backend.h"
 
 typedef struct {
 	uint32_t     start;
@@ -35,7 +34,12 @@
 	uint8_t     latch;
 } eeprom_state;
 
-typedef struct {
+
+typedef struct rom_info rom_info;
+
+#include "backend.h"
+
+struct rom_info {
 	char          *name;
 	memmap_chunk  *map;
 	uint8_t       *save_buffer;
@@ -51,7 +55,7 @@
 	uint16_t      mapper_start_index;
 	uint8_t       save_type;
 	uint8_t       regions;
-} rom_info;
+};
 
 tern_node *load_rom_db();
 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks);
--- a/sms.c	Tue Jan 03 23:03:30 2017 -0800
+++ b/sms.c	Wed Jan 04 20:43:22 2017 -0800
@@ -62,7 +62,7 @@
 		update_interrupts(sms);
 		return ret;
 	} else {
-		return vdp_data_port_read(sms->vdp);
+		return vdp_data_port_read_pbc(sms->vdp);
 	}
 }
 
@@ -104,6 +104,7 @@
 	void *old_value;
 	sms->ram[location & (sizeof(sms->ram)-1)] = value;
 	location &= 3;
+	sms->bank_regs[location] = value;
 	if (location) {
 		uint32_t idx = location - 1;
 		old_value = z80->mem_pointers[idx];
@@ -113,11 +114,53 @@
 			z80_invalidate_code_range(z80, idx ? idx * 0x4000 : 0x400, idx * 0x4000 + 0x4000);
 		}
 	} else {
-		//TODO: implement me
+		old_value = z80->mem_pointers[2];
+		if (value & 8) {
+			//cartridge RAM is enabled
+			z80->mem_pointers[2] = sms->cart_ram + (value & 4 ? (SMS_CART_RAM_SIZE/2) : 0);
+		} else {
+			//cartridge RAM is disabled
+			z80->mem_pointers[2] = sms->rom + (sms->bank_regs[3] << 14 & (sms->rom_size-1));
+		}
+		if (old_value != z80->mem_pointers[2]) {
+			//invalidate any code we translated for the relevant bank
+			z80_invalidate_code_range(z80, 0x8000, 0xC000);
+		}
 	}
 	return vcontext;
 }
 
+static void *cart_ram_write(uint32_t location, void *vcontext, uint8_t value)
+{
+	z80_context *z80 = vcontext;
+	sms_context *sms = z80->system;
+	if (sms->bank_regs[0] & 8) {
+		//cartridge RAM is enabled
+		location &= 0x3FFF;
+		z80->mem_pointers[2][location] = value;
+		z80_handle_code_write(0x8000 + location, z80);
+	}
+	return vcontext;
+}
+
+uint8_t debug_commands(system_header *system, char *input_buf)
+{
+	sms_context *sms = (sms_context *)system;
+	switch(input_buf[0])
+	{
+	case 'v':
+		if (input_buf[1] == 'r') {
+			vdp_print_reg_explain(sms->vdp);
+		} else if (input_buf[1] == 's') {
+			vdp_print_sprite_table(sms->vdp);
+		} else {
+			return 0;
+		}
+		break;
+	}
+	return 1;
+}
+
 static memmap_chunk io_map[] = {
 	{0x00, 0x40, 0xFF, 0, 0, 0, NULL, NULL, NULL, NULL,     memory_io_write},
 	{0x40, 0x80, 0xFF, 0, 0, 0, NULL, NULL, NULL, hv_read,  sms_psg_write},
@@ -232,7 +275,7 @@
 		memory_map[0] = (memmap_chunk){0x0000, 0x0400,  0xFFFF,             0, 0, MMAP_READ,                        rom,      NULL, NULL, NULL, NULL};
 		memory_map[1] = (memmap_chunk){0x0400, 0x4000,  0xFFFF,             0, 0, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL,     NULL, NULL, NULL, NULL};
 		memory_map[2] = (memmap_chunk){0x4000, 0x8000,  0x3FFF,             0, 1, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL,     NULL, NULL, NULL, NULL};
-		memory_map[3] = (memmap_chunk){0x8000, 0xC000,  0x3FFF,             0, 2, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL,     NULL, NULL, NULL, NULL};
+		memory_map[3] = (memmap_chunk){0x8000, 0xC000,  0x3FFF,             0, 2, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL,     NULL, NULL, NULL, cart_ram_write};
 		memory_map[4] = (memmap_chunk){0xC000, 0xFFFC,  sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE,   sms->ram, NULL, NULL, NULL, NULL};
 		memory_map[5] = (memmap_chunk){0xFFFC, 0x10000, 0xFFFF,             0, 0, MMAP_READ,                        ram_reg_overlap, NULL, NULL, NULL, mapper_write};
 	} else {
@@ -246,6 +289,7 @@
 	init_z80_opts(zopts, info_out->map, info_out->map_chunks, io_map, 4, 15, 0xFF);
 	sms->z80 = init_z80_context(zopts);
 	sms->z80->system = sms;
+	sms->z80->options->gen.debug_cmd_handler = debug_commands;
 	
 	sms->rom = rom;
 	sms->rom_size = rom_size;
--- a/sms.h	Tue Jan 03 23:03:30 2017 -0800
+++ b/sms.h	Wed Jan 04 20:43:22 2017 -0800
@@ -8,6 +8,7 @@
 #include "io.h"
 
 #define SMS_RAM_SIZE (8*1024)
+#define SMS_CART_RAM_SIZE (32*1024)
 
 typedef struct {
 	system_header header;
@@ -21,6 +22,8 @@
 	uint32_t      normal_clock;
 	uint8_t       should_return;
 	uint8_t       ram[SMS_RAM_SIZE];
+	uint8_t       bank_regs[4];
+	uint8_t       cart_ram[SMS_CART_RAM_SIZE];
 } sms_context;
 
 sms_context *alloc_configure_sms(void *rom, uint32_t rom_size, void *extra_rom, uint32_t extra_rom_size, uint32_t opts, uint8_t force_region, rom_info *info_out);
--- a/system.h	Tue Jan 03 23:03:30 2017 -0800
+++ b/system.h	Wed Jan 04 20:43:22 2017 -0800
@@ -1,8 +1,6 @@
 #ifndef SYSTEM_H_
 #define SYSTEM_H_
 #include <stdint.h>
-#include "arena.h"
-#include "romdb.h"
 
 typedef struct system_header system_header;
 typedef struct system_media system_media;
@@ -21,12 +19,16 @@
 
 typedef void (*system_fun)(system_header *);
 typedef uint16_t (*system_fun_r16)(system_header *);
-typedef void (*start_system_fun)(system_header *, char *);
+typedef void (*system_str_fun)(system_header *, char *);
+typedef uint8_t (*system_str_fun_r8)(system_header *, char *);
 typedef void (*speed_system_fun)(system_header *, uint32_t);
 
+#include "arena.h"
+#include "romdb.h"
+
 struct system_header {
 	system_header     *next_context;
-	start_system_fun  start_context;
+	system_str_fun    start_context;
 	system_fun        resume_context;
 	system_fun        load_save;
 	system_fun        persist_save;
--- a/vdp.c	Tue Jan 03 23:03:30 2017 -0800
+++ b/vdp.c	Wed Jan 04 20:43:22 2017 -0800
@@ -255,24 +255,42 @@
 
 void vdp_print_sprite_table(vdp_context * context)
 {
-	uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9;
-	uint16_t current_index = 0;
-	uint8_t count = 0;
-	do {
-		uint16_t address = current_index * 8 + sat_address;
-		uint16_t cache_address = current_index * 4;
-		uint8_t height = ((context->sat_cache[cache_address+2] & 0x3) + 1) * 8;
-		uint8_t width = (((context->sat_cache[cache_address+2]  >> 2) & 0x3) + 1) * 8;
-		int16_t y = ((context->sat_cache[cache_address] & 0x3) << 8 | context->sat_cache[cache_address+1]) & 0x1FF;
-		int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF;
-		uint16_t link = context->sat_cache[cache_address+3] & 0x7F;
-		uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
-		uint8_t pri = context->vdpmem[address + 4] >> 7;
-		uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
-		printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
-		current_index = link;
-		count++;
-	} while (current_index != 0 && count < 80);
+	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
+		uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9;
+		uint16_t current_index = 0;
+		uint8_t count = 0;
+		do {
+			uint16_t address = current_index * 8 + sat_address;
+			uint16_t cache_address = current_index * 4;
+			uint8_t height = ((context->sat_cache[cache_address+2] & 0x3) + 1) * 8;
+			uint8_t width = (((context->sat_cache[cache_address+2]  >> 2) & 0x3) + 1) * 8;
+			int16_t y = ((context->sat_cache[cache_address] & 0x3) << 8 | context->sat_cache[cache_address+1]) & 0x1FF;
+			int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF;
+			uint16_t link = context->sat_cache[cache_address+3] & 0x7F;
+			uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
+			uint8_t pri = context->vdpmem[address + 4] >> 7;
+			uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
+			printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
+			current_index = link;
+			count++;
+		} while (current_index != 0 && count < 80);
+	} else {
+		uint16_t sat_address = (context->regs[REG_SAT] & 0x7E) << 7;
+		for (int i = 0; i < 64; i++)
+		{
+			uint8_t y = context->vdpmem[sat_address + (i ^ 1)];
+			if (y >= 0xD0) {
+				break;
+			}
+			uint8_t x = context->vdpmem[sat_address + 0x80 + i*2 + 1];
+			uint16_t tile_address = context->vdpmem[sat_address + 0x80 + i*2] * 32
+				+ (context->regs[REG_STILE_BASE] << 11 & 0x2000);
+			if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) {
+				tile_address &= ~32;
+			}
+			printf("Sprite %d: X=%d, Y=%d, Pat=%X\n", i, x, y, tile_address);
+		}
+	}
 }
 
 #define VRAM_READ 0 //0000
@@ -344,17 +362,32 @@
 	       context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full",
 	           hscroll[context->regs[REG_MODE_3] & 0x3],
 	       context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled");
-	printf("\n**Table Group**\n"
-	       "02: %.2X | Scroll A Name Table:    $%.4X\n"
-	       "03: %.2X | Window Name Table:      $%.4X\n"
-	       "04: %.2X | Scroll B Name Table:    $%.4X\n"
-	       "05: %.2X | Sprite Attribute Table: $%.4X\n"
-	       "0D: %.2X | HScroll Data Table:     $%.4X\n",
-	       context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10,
-	       context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10,
-	       context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13,
-	       context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x7E : 0x7F)) << 9,
-	       context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10);
+	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
+		printf("\n**Table Group**\n"
+			   "02: %.2X | Scroll A Name Table:    $%.4X\n"
+			   "03: %.2X | Window Name Table:      $%.4X\n"
+			   "04: %.2X | Scroll B Name Table:    $%.4X\n"
+			   "05: %.2X | Sprite Attribute Table: $%.4X\n"
+			   "0D: %.2X | HScroll Data Table:     $%.4X\n",
+			   context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10,
+			   context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10,
+			   context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13,
+			   context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x7E : 0x7F)) << 9,
+			   context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10);
+	} else {
+		printf("\n**Table Group**\n"
+			   "02: %.2X | Background Name Table:  $%.4X\n"
+			   "05: %.2X | Sprite Attribute Table: $%.4X\n"
+			   "06: %.2X | Sprite Tile Base:       $%.4X\n"
+			   "08: %.2X | Background X Scroll:    %d\n"
+			   "09: %.2X | Background Y Scroll:    %d\n",
+			   context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0xE) << 10,
+			   context->regs[REG_SAT], (context->regs[REG_SAT] & 0x7E) << 7,
+			   context->regs[REG_STILE_BASE], (context->regs[REG_STILE_BASE] & 2) << 11,
+			   context->regs[REG_X_SCROLL], context->regs[REG_X_SCROLL],
+			   context->regs[REG_Y_SCROLL], context->regs[REG_Y_SCROLL]);
+			   
+	}
 	char * sizes[] = {"32", "64", "invalid", "128"};
 	printf("\n**Misc Group**\n"
 	       "07: %.2X | Backdrop Color: $%X\n"
@@ -2330,6 +2363,20 @@
 	return context->prefetch;
 }
 
+uint8_t vdp_data_port_read_pbc(vdp_context * context)
+{
+	if (context->flags & FLAG_PENDING) {
+		context->flags &= ~FLAG_PENDING;
+		//Should these be cleared here?
+		context->flags &= ~FLAG_READ_FETCHED;
+		context->flags2 &= ~FLAG2_READ_PENDING;
+	}
+	context->flags &= ~FLAG_READ_FETCHED;
+	//Should this happen after the prefetch or after the read?
+	context->address += context->regs[REG_AUTOINC];
+	return context->prefetch;
+}
+
 uint16_t vdp_hv_counter_read(vdp_context * context)
 {
 	if ((context->regs[REG_MODE_2] & BIT_MODE_5) && (context->regs[REG_MODE_1] & BIT_HVC_LATCH)) {
--- a/vdp.h	Tue Jan 03 23:03:30 2017 -0800
+++ b/vdp.h	Wed Jan 04 20:43:22 2017 -0800
@@ -212,6 +212,7 @@
 void vdp_test_port_write(vdp_context * context, uint16_t value);
 uint16_t vdp_control_port_read(vdp_context * context);
 uint16_t vdp_data_port_read(vdp_context * context);
+uint8_t vdp_data_port_read_pbc(vdp_context * context);
 uint16_t vdp_hv_counter_read(vdp_context * context);
 uint16_t vdp_test_port_read(vdp_context * context);
 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction);