changeset 866:69a6ec208111

Menu ROM now pulls real file names from the OS rather than using a fake list
author Michael Pavone <pavone@retrodev.com>
date Fri, 06 Nov 2015 12:19:39 -0800
parents 305c85c0b954
children bacd67a82d58
files Makefile blastem.h config.c menu.c menu.h menu.s68 rom.db romdb.c util.c util.h
diffstat 10 files changed, 295 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Nov 06 11:44:51 2015 -0800
+++ b/Makefile	Fri Nov 06 12:19:39 2015 -0800
@@ -107,7 +107,7 @@
 AUDIOOBJS=ym2612.o psg.o wave.o
 CONFIGOBJS=config.o tern.o util.o
 
-MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
+MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
 
 ifeq ($(CPU),x86_64)
 CFLAGS+=-DX86_64 -m64
--- a/blastem.h	Fri Nov 06 11:44:51 2015 -0800
+++ b/blastem.h	Fri Nov 06 12:19:39 2015 -0800
@@ -24,6 +24,7 @@
 	psg_context    *psg;
 	uint16_t       *work_ram;
 	uint8_t        *zram;
+	void           *extra;
 	uint8_t        *save_storage;
 	eeprom_map     *eeprom_map;
 	uint32_t       num_eeprom;
--- a/config.c	Fri Nov 06 11:44:51 2015 -0800
+++ b/config.c	Fri Nov 06 12:19:39 2015 -0800
@@ -43,7 +43,7 @@
 	config_data = started ? NULL : *state;
 	while ((curline = strtok_r(config_data, "\n", state)))
 	{
-		
+
 		config_data = NULL;
 		curline = strip_ws(curline);
 		int len = strlen(curline);
@@ -61,7 +61,7 @@
 			}
 			fatal_error("unexpected } on line %d\n", *line);
 		}
-		
+
 		char * end = curline + len - 1;
 		if (*end == '{') {
 			*end = 0;
@@ -128,7 +128,7 @@
 	if (!config_size) {
 		goto config_empty;
 	}
-	
+
 	char * config_data = malloc(config_size+1);
 	if (SDL_RWread(rw, config_data, 1, config_size) != config_size) {
 		goto config_read_fail;
@@ -152,12 +152,12 @@
 	if (ret) {
 		return ret;
 	}
-	
+
 	ret = parse_config_file_assets("default.cfg");
 	if (ret) {
 		return ret;
 	}
-	
+
 	fatal_error("Failed to find a config file in internal storage or in the blastem APK\n");
 	//this will never get reached, but the compiler doesn't know that. Let's make it happy
 	return NULL;
@@ -169,25 +169,26 @@
 {
 	char * exe_dir;
 	char * home = get_home_dir();
-	if (home) {		
+	tern_node *ret;
+	if (home) {
 		char * path = alloc_concat(home, "/.config/blastem/blastem.cfg");
-		tern_node * ret = parse_config_file(path);
-		free(path);
-		if (ret) {
-			return ret;
-		}
-	}
-	
-	exe_dir = get_exe_dir();
-	if (exe_dir) {		
-		path = alloc_concat(exe_dir, "/default.cfg");
 		ret = parse_config_file(path);
 		free(path);
 		if (ret) {
 			return ret;
 		}
 	}
-	
+
+	exe_dir = get_exe_dir();
+	if (exe_dir) {
+		char *path = alloc_concat(exe_dir, "/default.cfg");
+		ret = parse_config_file(path);
+		free(path);
+		if (ret) {
+			return ret;
+		}
+	}
+
 	fatal_error("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n");
 	//this will never get reached, but the compiler doesn't know that. Let's make it happy
 	return NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menu.c	Fri Nov 06 12:19:39 2015 -0800
@@ -0,0 +1,85 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "blastem.h"
+#include "menu.h"
+#include "backend.h"
+#include "util.h"
+
+
+uint16_t menu_read_w(uint32_t address, void * context)
+{
+	//This should return the status of the last request with 0
+	//meaning either the request is complete or no request is pending
+	//in the current implementation, the operations happen instantly
+	//in emulated time so we can always return 0
+	return 0;
+}
+
+void * menu_write_w(uint32_t address, void * context, uint16_t value)
+{
+	m68k_context *m68k = context;
+	genesis_context *gen = m68k->system;
+	menu_context *menu = gen->extra;
+	if (!menu) {
+		gen->extra = menu = calloc(1, sizeof(menu_context));
+		menu->curpath = strdup(get_home_dir());
+	}
+	if (menu->state) {
+		uint32_t dst = menu->latch << 16 | value;
+		switch (address >> 2)
+		{
+		case 0: {
+			size_t num_entries;
+			dir_entry *entries = get_dir_list(menu->curpath, &num_entries);
+			for (size_t i = 0; i < num_entries; i++)
+			{
+				uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
+				if (!dest) {
+					break;
+				}
+				*(dest++) = entries[i].is_dir;
+				*(dest++) = 1;
+				dst += 2;
+				uint8_t term = 0;
+				for (char *cpos = entries[i].name; *cpos; cpos++)
+				{
+					dest[1] = *cpos;
+					dest[0] = cpos[1];
+					if (cpos[1]) {
+						cpos++;
+					} else {
+						term = 1;
+					}
+					dst += 2;
+					if (!(dst & 0xFFFF)) {
+						//we may have walked off the end of a memory block, get a fresh native pointer
+						dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
+						if (!dest) {
+							break;
+						}
+					} else {
+						dest += 2;
+					}
+				}
+				if (!term) {
+					*(dest++) = 0;
+					*dest = 0;
+					dst += 2;
+				}
+			}
+			free_dir_list(entries, num_entries);
+			break;
+		}
+		default:
+			fprintf(stderr, "WARNING: write to undefined menu port %X\n", address);
+		}
+		menu->state = 0;
+	} else {
+		menu->latch = value;
+		menu->state = 1;
+	}
+
+	return context;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menu.h	Fri Nov 06 12:19:39 2015 -0800
@@ -0,0 +1,18 @@
+/*
+ Copyright 2015 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef MENU_H_
+#define MENU_H_
+typedef struct {
+	char     *curpath;
+	uint16_t latch;
+	uint16_t state;
+} menu_context;
+
+
+uint16_t menu_read_w(uint32_t address, void * context);
+void * menu_write_w(uint32_t address, void * context, uint16_t value);
+
+#endif // MENU_H_
--- a/menu.s68	Fri Nov 06 11:44:51 2015 -0800
+++ b/menu.s68	Fri Nov 06 12:19:39 2015 -0800
@@ -84,7 +84,7 @@
 	dc.b "Menu            "
 	dc.b "                "
 	dc.b "                "
-	dc.b "GM MK-00000-00", 0, 0
+	dc.b "MP BlstMenu-00", 0, 0
 	dc.b "                "
 	dc.l $0, rom_end-1, $FF0000, $FFFFFF
 	dc.b "                "
@@ -92,7 +92,7 @@
 	dc.b "                "
 	dc.b "                "
 	dc.b "JUE "
-	
+
 ;register addresses
 VDP_DATA  equ $C00000
 VDP_CTRL  equ $C00004
@@ -139,21 +139,21 @@
 vdpreg macro
 	dc.w (((\1) << 8) | $8000 | (\2))
 	endm
-	
+
 ;Writes a normal VDP command to the control port
 ;\1 - VDP address
 ;\2 - Access type
 vdpaccess macro
 	move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), (a1)
 	endm
-	
+
 ;Writes a DMA command to the control port
 ;\1 - Destination address
 ;\2 - Destination type
 startdma macro
 	move.l #(\2 | VDP_DMA_FLAG | (\1 << 16) & $3FFF0000 | (\1 >> 14) & 3), (a1)
 	endm
-	
+
 DMA_SRC_68K  equ 0
 DMA_SRC_VRAM equ $C0
 DMA_SRC_FILL equ $80
@@ -162,14 +162,19 @@
 	move.l #($95009600 + (\1) << 15 & $FF0000 + (\1) >> 9 & $FF), (a1)
 	move.w #($9700 + (\1) >> 17 & $7F | (\2)), (a1)
 	endm
-	
+
+dir_buffer equ $100000
+menu_port  equ $180000
+
+MAX_DISPLAY equ 24
+
 	rsset $FFFF8000
 x_pos       rs.w 1
 base_cmd    rs.l 1
 sprite_list rs.l 160
 num_sprites rs.b 1
 last_pad    rs.b 1
-	
+
 int_6:
 	dmasrc sprite_list, DMA_SRC_68K
 	;set DMA length
@@ -184,7 +189,7 @@
 	move.b d1, d0
 	move.l d0, (a1)
 	startdma $C000, VDP_VRAM_WRITE
-	
+
 	lea PAD1_DATA, a2
 	move.b #$40, (a2)
 	move.b (a2), d0
@@ -200,14 +205,14 @@
 	eor.b d0, d1
 	and.b d0, d1
 	move.b d0, (last_pad).w
-	
+
 	moveq #16, d2
 	btst #1, d1
 	bne down
 	btst #0, d1
 	bne up
 	rte
-	
+
 down:
 	add.w d2, (sprite_list).w
 	add.w d2, (sprite_list+8).w
@@ -216,11 +221,11 @@
 	sub.w d2, (sprite_list).w
 	sub.w d2, (sprite_list+8).w
 	rte
-	
+
 int_4:
 empty_handler:
 	rte
-	
+
 
 
 initial_regs:
@@ -241,13 +246,13 @@
 start:
 	lea $C00000, a0
 	lea $C00004, a1
-	
+
 	moveq #(end_initial_regs-initial_regs-1), d0
 	lea initial_regs.w, a2
 .regloop
 	move.w (a2)+, (a1)
 	dbra d0, .regloop
-	
+
 	vdpaccess $0, VDP_CRAM_WRITE
 	move.w #$020, (a0)
 	move.w #$EEE, (a0)
@@ -277,43 +282,76 @@
 ploop:
 	move.l d0, (a0)
 	dbra d1, ploop
-	
+
 	;setup SAT
 	;;vdpaccess $C000, VDP_VRAM_WRITE
-	
+
 	lea sprite_list.w, a2
 	;left arrow
 	move.l #$01080501, (a2)+
 	move.l #$807F0086, (a2)+
-	
+
 	;right arrow
 	move.l #$01080500, (a2)+
 	move.l #$887F01AA, (a2)+
 	move.b #2, num_sprites.w
-	
+
 	move.l #$40860002, d3
 	move.l d3, (a1)
 	move.l d3, base_cmd.w
 
-	lea Message(pc), a6
+	lea dir_buffer, a6
+	lea menu_port, a2
+	move.l a6, (a2)
+
+wait_complete:
+	tst.w (a2)
+	bne wait_complete
+
+	moveq #MAX_DISPLAY-1, d7
+file_loop:
+	tst.b (a6)+
+	addq #1, a6 ;TODO: Do something with directory flag
+
+	cmp.b #$2E, (a6)
+	bne normal
+	cmp.b #$2E, (1, a6)
+	beq normal
+	addq #1, a6
+.skip_loop:
+	tst.b (a6)+
+	bne .skip_loop
+	addq #1, d7
+	move.l a6, d6
+	bra skip
+normal:
 	moveq #0, d0
 	bsr print_string
-	
+	move.l a6, d6
+
+	lea Newline(pc), a6
+	bsr print_string
+
+skip:
+	;word align pointer
+	addq #1, d6
+	and.w #$FFFE, d6
+	move.l d6, a6
+
+	dbra d7, file_loop
+
 	;setup gamepad in port 1
 	move.b #$40, PAD1_CTRL
-	
+
 	move.w #$8174, (a1) ;enable display, vertical interrupts, DMA
-	
+
 
 wait_forever
 	stop #2500
 	bra wait_forever
 
-Message:
-	dc.b "Journey From Darkness - Strider Returns (U) [c][!].bin", $A
-	dc.b "Toejam & Earl in Panic on Funkotron (U) [!].bin", $A
-	dc.b "Fire Shark (U) [c][!].bin", $A
-	dc.b "Sonic and Knuckles (W) [!].bin", 0
+Newline:
+	dc.b $A, 0
 
 	align 1
 
@@ -378,5 +416,5 @@
 	dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1
 	dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
 	dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1
-	
+
 rom_end:
--- a/rom.db	Fri Nov 06 11:44:51 2015 -0800
+++ b/rom.db	Fri Nov 06 12:19:39 2015 -0800
@@ -353,4 +353,21 @@
 			offset 80000
 		}
 	}
-}
\ No newline at end of file
+}
+BlstMenu {
+	map {
+		0 {
+			device ROM
+			last FFFFF
+		}
+		100000 {
+			device RAM
+			size 80000
+			last 17FFFF
+		}
+		180000 {
+			device MENU
+			last 1FFFFF
+		}
+	}
+}
--- a/romdb.c	Fri Nov 06 11:44:51 2015 -0800
+++ b/romdb.c	Fri Nov 06 12:19:39 2015 -0800
@@ -4,6 +4,7 @@
 #include "romdb.h"
 #include "util.h"
 #include "blastem.h"
+#include "menu.h"
 
 #define TITLE_START 0x150
 #define TITLE_END (TITLE_START+48)
@@ -335,7 +336,7 @@
 	if (!map) {
 		fatal_error("Could not find EEPROM map for address %X\n", address);
 	}
-	
+
 	uint16_t expanded, mask;
 	if (address & 1) {
 		expanded = value;
@@ -405,7 +406,7 @@
 {
 	uint8_t *last = rom + TITLE_END - 1;
 	uint8_t *src = rom + TITLE_START;
-	
+
 	while (last > src && (*last <=  0x20 || *last >= 0x80))
 	{
 		last--;
@@ -490,24 +491,24 @@
 		}
 		info->save_size = save_size;
 		info->save_buffer = malloc(save_size);
-		
+
 		info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3);
 		info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
 		memset(info->map, 0, sizeof(memmap_chunk)*2);
 		memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks);
-		
+
 		if (ram_start >= rom_end) {
 			info->map[0].end = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
 			//TODO: ROM mirroring
 			info->map[0].mask = 0xFFFFFF;
 			info->map[0].flags = MMAP_READ;
 			info->map[0].buffer = rom;
-			
+
 			info->map[1].start = ram_start;
 			info->map[1].mask = info->save_mask;
 			info->map[1].end = ram_end + 1;
 			info->map[1].flags = MMAP_READ | MMAP_WRITE;
-			
+
 			if (ram_flags == RAM_FLAG_ODD) {
 				info->map[1].flags |= MMAP_ONLY_ODD;
 			} else if (ram_flags == RAM_FLAG_EVEN) {
@@ -520,7 +521,7 @@
 			info->map[0].mask = 0xFFFFFF;
 			info->map[0].flags = MMAP_READ;
 			info->map[0].buffer = rom;
-			
+
 			info->map[1].start = 0x200000;
 			info->map[1].end = 0x400000;
 			info->map[1].mask = 0x1FFFFF;
@@ -531,7 +532,7 @@
 			info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
 			info->map[1].write_8 = (write_8_fun)write_sram_area_b;
 			info->map[1].buffer = cart + 0x200000;
-			
+
 			memmap_chunk *last = info->map + info->map_chunks - 1;
 			memset(last, 0, sizeof(memmap_chunk));
 			last->start = 0xA13000;
@@ -545,7 +546,7 @@
 		info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
 		memset(info->map, 0, sizeof(memmap_chunk));
 		memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks);
-		
+
 		info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000;
 		info->map[0].mask = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
 		info->map[0].flags = MMAP_READ;
@@ -703,7 +704,7 @@
 	} else if (!strcmp(dtype, "EEPROM")) {
 		process_eeprom_def(key, state);
 		add_eeprom_map(node, start, end, state);
-		
+
 		map->write_16 = write_eeprom_i2c_w;
 		map->write_8 = write_eeprom_i2c_b;
 		map->read_16 = read_eeprom_i2c_w;
@@ -719,6 +720,22 @@
 			map->flags |= MMAP_ONLY_EVEN;
 		}
 		map->mask = calc_mask(state->info->save_size, start, end);
+	} else if (!strcmp(dtype, "RAM")) {
+		uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16);
+		if (!size || size > map->end - map->start) {
+			size = map->end - map->start;
+		}
+		map->buffer = malloc(size);
+		map->mask = calc_mask(size, start, end);
+		map->flags = MMAP_READ | MMAP_WRITE;
+		char *bus = tern_find_ptr_default(node, "bus", "both");
+		if (!strcmp(dtype, "odd")) {
+			map->flags |= MMAP_ONLY_ODD;
+		} else if (!strcmp(dtype, "even")) {
+			map->flags |= MMAP_ONLY_EVEN;
+		} else {
+			map->flags |= MMAP_CODE;
+		}
 	} else if (!strcmp(dtype, "Sega mapper")) {
 		state->info->mapper_start_index = state->ptr_index++;
 		state->info->map_chunks+=7;
@@ -760,6 +777,12 @@
 		map->mask = 0xFF;
 		map->write_16 = (write_16_fun)write_bank_reg_w;
 		map->write_8 = (write_8_fun)write_bank_reg_b;
+	} else if (!strcmp(dtype, "MENU")) {
+		//fake hardware for supporting menu
+		map->buffer = NULL;
+		map->mask = 0xFF;
+		map->write_16 = menu_write_w;
+		map->read_16 = menu_read_w;
 	} else {
 		fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key);
 	}
@@ -778,7 +801,7 @@
 			break;
 		}
 		product_id[i] = rom[GAME_ID_OFF + i];
-		
+
 	}
 	printf("Product ID: %s\n", product_id);
 	tern_node * entry = tern_find_ptr(rom_db, product_id);
@@ -794,7 +817,7 @@
 	} else {
 		info.name = get_header_name(rom);
 	}
-	
+
 	char *dbreg = tern_find_ptr(entry, "regions");
 	info.regions = 0;
 	if (dbreg) {
@@ -806,7 +829,7 @@
 	if (!info.regions) {
 		info.regions = get_header_regions(rom);
 	}
-	
+
 	tern_node *map = tern_find_ptr(entry, "map");
 	if (map) {
 		info.save_type = SAVE_NONE;
@@ -828,6 +851,6 @@
 	} else {
 		add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
 	}
-	
+
 	return info;
 }
--- a/util.c	Fri Nov 06 11:44:51 2015 -0800
+++ b/util.c	Fri Nov 06 12:19:39 2015 -0800
@@ -11,6 +11,7 @@
 
 #include "blastem.h" //for headless global
 #include "render.h" //for render_errorbox
+#include "util.h"
 
 char * alloc_concat(char * first, char * second)
 {
@@ -277,5 +278,46 @@
 	}
 	return exe_dir;
 }
+#include <dirent.h>
+
+dir_entry *get_dir_list(char *path, size_t *numret)
+{
+	DIR *d = opendir(path);
+	if (!d) {
+		if (numret) {
+			*numret = 0;
+		}
+		return NULL;
+	}
+	size_t storage = 64;
+	dir_entry *ret = malloc(sizeof(dir_entry) * storage);
+	size_t pos = 0;
+	struct dirent* entry;
+	while (entry = readdir(d))
+	{
+		if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_DIR) {
+			continue;
+		}
+		if (pos == storage) {
+			storage = storage * 2;
+			ret = realloc(ret, sizeof(dir_entry) * storage);
+		}
+		ret[pos].name = strdup(entry->d_name);
+		ret[pos++].is_dir = entry->d_type == DT_DIR;
+	}
+	if (numret) {
+		*numret = pos;
+	}
+	return ret;
+}
+
+void free_dir_list(dir_entry *list, size_t numentries)
+{
+	for (size_t i = 0; i < numentries; i++)
+	{
+		free(list[i].name);
+	}
+	free(list);
+}
 
 #endif
--- a/util.h	Fri Nov 06 11:44:51 2015 -0800
+++ b/util.h	Fri Nov 06 12:19:39 2015 -0800
@@ -3,6 +3,11 @@
 
 #include <stdio.h>
 
+typedef struct {
+	char    *name;
+	uint8_t is_dir;
+} dir_entry;
+
 //Utility functions
 
 //Allocates a new string containing the concatenation of first and second
@@ -23,6 +28,10 @@
 char * get_exe_dir();
 //Returns the user's home directory
 char * get_home_dir();
+//Retunrs an array of normal files and directories residing in a directory
+dir_entry *get_dir_list(char *path, size_t *numret);
+//Frees a dir list returned by get_dir_list
+void free_dir_list(dir_entry *list, size_t numentries);
 //Returns the contents of a symlink in a newly allocated string
 char * readlink_alloc(char * path);
 //Prints an error message to stderr and to a message box if not in headless mode and then exits